Skip to main content

xlsynth/
vast.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! APIs that wrap the Verilog AST building facilities inside of XLS.
4
5#![allow(unused)]
6#![allow(clippy::arc_with_non_send_sync)]
7
8use xlsynth_sys::{self as sys};
9
10use std::{
11    ffi::CString,
12    os::raw::c_char,
13    sync::{Arc, Mutex},
14};
15
16use crate::{
17    c_str_to_rust, ir_value::IrFormatPreference, lib_support::xls_format_preference_from_string,
18    xls_parse_typed_value, XlsynthError,
19};
20
21// No additional imports needed.
22
23// Represents the direction of a module port.
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum ModulePortDirection {
26    Input,
27    Output,
28}
29
30pub struct ModulePort {
31    inner: *mut sys::CVastModulePort,
32    parent: Arc<Mutex<VastFilePtr>>, // Keep the VAST file alive while this port exists.
33}
34
35impl ModulePort {
36    pub fn direction(&self) -> ModulePortDirection {
37        let _locked = self.parent.lock().unwrap();
38        let dir = unsafe { sys::xls_vast_verilog_module_port_get_direction(self.inner) };
39        match dir {
40            x if x == sys::XLS_VAST_MODULE_PORT_DIRECTION_INPUT => ModulePortDirection::Input,
41            x if x == sys::XLS_VAST_MODULE_PORT_DIRECTION_OUTPUT => ModulePortDirection::Output,
42            _ => panic!("Invalid port direction: {}", dir),
43        }
44    }
45
46    pub fn name(&self) -> String {
47        let _locked = self.parent.lock().unwrap();
48        let def_ptr = unsafe { sys::xls_vast_verilog_module_port_get_def(self.inner) };
49        let c_str = unsafe { sys::xls_vast_def_get_name(def_ptr) };
50        unsafe { c_str_to_rust(c_str) }
51    }
52
53    pub fn data_type(&self) -> VastDataType {
54        let _locked = self.parent.lock().unwrap();
55        let def_ptr = unsafe { sys::xls_vast_verilog_module_port_get_def(self.inner) };
56        let dt_ptr = unsafe { sys::xls_vast_def_get_data_type(def_ptr) };
57        VastDataType {
58            inner: dt_ptr,
59            parent: self.parent.clone(),
60        }
61    }
62
63    /// Returns the width (bit count) of this port if determinable; otherwise 0.
64    pub fn width(&self) -> i64 {
65        self.data_type()
66            .flat_bit_count_as_int64()
67            .unwrap_or_default()
68    }
69}
70
71impl VastDataType {
72    /// Returns the declared width for bit-vector types as an i64.
73    pub fn width_as_int64(&self) -> Result<i64, XlsynthError> {
74        let _locked = self.parent.lock().unwrap();
75        let mut width_out: i64 = 0;
76        let mut error_out: *mut c_char = std::ptr::null_mut();
77        let success = unsafe {
78            sys::xls_vast_data_type_width_as_int64(self.inner, &mut width_out, &mut error_out)
79        };
80        if success {
81            Ok(width_out)
82        } else {
83            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
84        }
85    }
86
87    /// Returns the total flat bit count for composite types as an i64.
88    pub fn flat_bit_count_as_int64(&self) -> Result<i64, XlsynthError> {
89        let _locked = self.parent.lock().unwrap();
90        let mut count_out: i64 = 0;
91        let mut error_out: *mut c_char = std::ptr::null_mut();
92        let success = unsafe {
93            sys::xls_vast_data_type_flat_bit_count_as_int64(
94                self.inner,
95                &mut count_out,
96                &mut error_out,
97            )
98        };
99        if success {
100            Ok(count_out)
101        } else {
102            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
103        }
104    }
105
106    /// Returns an expression representing the width, if any.
107    pub fn width_expr(&self) -> Option<Expr> {
108        let _locked = self.parent.lock().unwrap();
109        let expr_ptr = unsafe { sys::xls_vast_data_type_width(self.inner) };
110        if expr_ptr.is_null() {
111            None
112        } else {
113            Some(Expr {
114                inner: expr_ptr,
115                parent: self.parent.clone(),
116            })
117        }
118    }
119
120    /// Returns true if the type is signed.
121    pub fn is_signed(&self) -> bool {
122        let _locked = self.parent.lock().unwrap();
123        unsafe { sys::xls_vast_data_type_is_signed(self.inner) }
124    }
125}
126
127// Extend VastModule with querying capabilities.
128impl VastModule {
129    /// Returns all ports (both inputs and outputs) on this module.
130    pub fn ports(&self) -> Vec<ModulePort> {
131        let _locked = self.parent.lock().unwrap();
132        let mut count: usize = 0;
133        let ports_ptr = unsafe { sys::xls_vast_verilog_module_get_ports(self.inner, &mut count) };
134        if ports_ptr.is_null() || count == 0 {
135            return Vec::new();
136        }
137        let slice = unsafe { std::slice::from_raw_parts(ports_ptr, count) };
138        let result = slice
139            .iter()
140            .map(|&ptr| ModulePort {
141                inner: ptr,
142                parent: self.parent.clone(),
143            })
144            .collect::<Vec<_>>();
145        // Free the array returned by the C API (but not the individual port objects).
146        unsafe { sys::xls_vast_verilog_module_free_ports(ports_ptr, count) };
147        result
148    }
149
150    /// Returns only the input ports for this module.
151    pub fn input_ports(&self) -> Vec<ModulePort> {
152        self.ports()
153            .into_iter()
154            .filter(|p| p.direction() == ModulePortDirection::Input)
155            .collect()
156    }
157
158    /// Returns only the output ports for this module.
159    pub fn output_ports(&self) -> Vec<ModulePort> {
160        self.ports()
161            .into_iter()
162            .filter(|p| p.direction() == ModulePortDirection::Output)
163            .collect()
164    }
165}
166
167struct VastFilePtr(pub *mut sys::CVastFile);
168
169enum VastOperatorKind {
170    // unary operators
171    Negate = 0,
172    BitwiseNot = 1,
173    LogicalNot = 2,
174    AndReduce = 3,
175    OrReduce = 4,
176    XorReduce = 5,
177
178    // binary operators
179    Add = 6,
180    LogicalAnd = 7,
181    BitwiseAnd = 8,
182    Ne = 9,
183    CaseNe = 10,
184    Eq = 11,
185    CaseEq = 12,
186    Ge = 13,
187    Gt = 14,
188    Le = 15,
189    Lt = 16,
190    Div = 17,
191    Mod = 18,
192    Mul = 19,
193    Power = 20,
194    BitwiseOr = 21,
195    LogicalOr = 22,
196    BitwiseXor = 23,
197    Shll = 24,
198    Shra = 25,
199    Shrl = 26,
200    Sub = 27,
201    NeX = 28,
202    EqX = 29,
203}
204
205impl Drop for VastFilePtr {
206    fn drop(&mut self) {
207        unsafe { sys::xls_vast_verilog_file_free(self.0) }
208    }
209}
210
211#[derive(Clone)]
212pub struct VastDataType {
213    inner: *mut sys::CVastDataType,
214    parent: Arc<Mutex<VastFilePtr>>,
215}
216
217#[derive(Clone)]
218pub struct LogicRef {
219    inner: *mut sys::CVastLogicRef,
220    parent: Arc<Mutex<VastFilePtr>>,
221}
222
223impl LogicRef {
224    pub fn name(&self) -> String {
225        let locked = self.parent.lock().unwrap();
226        let inner = unsafe { sys::xls_vast_logic_ref_get_name(self.inner) };
227        unsafe { c_str_to_rust(inner) }
228    }
229
230    pub fn to_expr(&self) -> Expr {
231        let locked = self.parent.lock().unwrap();
232        let inner = unsafe { sys::xls_vast_logic_ref_as_expression(self.inner) };
233        Expr {
234            inner,
235            parent: self.parent.clone(),
236        }
237    }
238    pub fn to_indexable_expr(&self) -> IndexableExpr {
239        let locked = self.parent.lock().unwrap();
240        let inner = unsafe { sys::xls_vast_logic_ref_as_indexable_expression(self.inner) };
241        IndexableExpr {
242            inner,
243            parent: self.parent.clone(),
244        }
245    }
246}
247
248#[derive(Clone)]
249pub struct Expr {
250    inner: *mut sys::CVastExpression,
251    parent: Arc<Mutex<VastFilePtr>>,
252}
253
254impl Expr {
255    pub fn emit(&self) -> String {
256        let _locked = self.parent.lock().unwrap();
257        let c_str = unsafe { sys::xls_vast_expression_emit(self.inner) };
258        unsafe { c_str_to_rust(c_str) }
259    }
260}
261
262#[derive(Clone)]
263pub struct IndexableExpr {
264    inner: *mut sys::CVastIndexableExpression,
265    parent: Arc<Mutex<VastFilePtr>>,
266}
267
268impl IndexableExpr {
269    pub fn to_expr(&self) -> Expr {
270        let locked = self.parent.lock().unwrap();
271        let inner = unsafe { sys::xls_vast_indexable_expression_as_expression(self.inner) };
272        Expr {
273            inner,
274            parent: self.parent.clone(),
275        }
276    }
277}
278
279pub struct VastModule {
280    inner: *mut sys::CVastModule,
281    parent: Arc<Mutex<VastFilePtr>>,
282}
283
284pub struct Slice {
285    inner: *mut sys::CVastSlice,
286    parent: Arc<Mutex<VastFilePtr>>,
287}
288
289impl Slice {
290    pub fn to_expr(&self) -> Expr {
291        let locked = self.parent.lock().unwrap();
292        let inner = unsafe { sys::xls_vast_slice_as_expression(self.inner) };
293        Expr {
294            inner,
295            parent: self.parent.clone(),
296        }
297    }
298}
299
300pub struct Index {
301    inner: *mut sys::CVastIndex,
302    parent: Arc<Mutex<VastFilePtr>>,
303}
304
305impl Index {
306    pub fn to_expr(&self) -> Expr {
307        let locked = self.parent.lock().unwrap();
308        let inner = unsafe { sys::xls_vast_index_as_expression(self.inner) };
309        Expr {
310            inner,
311            parent: self.parent.clone(),
312        }
313    }
314
315    pub fn to_indexable_expr(&self) -> IndexableExpr {
316        let locked = self.parent.lock().unwrap();
317        let inner = unsafe { sys::xls_vast_index_as_indexable_expression(self.inner) };
318        IndexableExpr {
319            inner,
320            parent: self.parent.clone(),
321        }
322    }
323}
324
325pub struct Instantiation {
326    inner: *mut sys::CVastInstantiation,
327    parent: Arc<Mutex<VastFilePtr>>,
328}
329
330pub struct BlankLine {
331    inner: *mut sys::CVastBlankLine,
332    parent: Arc<Mutex<VastFilePtr>>,
333}
334
335pub struct InlineVerilogStatement {
336    inner: *mut sys::CVastInlineVerilogStatement,
337    parent: Arc<Mutex<VastFilePtr>>,
338}
339
340pub struct Comment {
341    inner: *mut sys::CVastComment,
342    parent: Arc<Mutex<VastFilePtr>>,
343}
344
345pub struct MacroRef {
346    inner: *mut sys::CVastMacroRef,
347    parent: Arc<Mutex<VastFilePtr>>,
348}
349
350pub struct MacroStatement {
351    inner: *mut sys::CVastMacroStatement,
352    parent: Arc<Mutex<VastFilePtr>>,
353}
354
355pub struct ContinuousAssignment {
356    inner: *mut sys::CVastContinuousAssignment,
357    parent: Arc<Mutex<VastFilePtr>>,
358}
359
360pub struct VastAlwaysBase {
361    inner: *mut sys::CVastAlwaysBase,
362    parent: Arc<Mutex<VastFilePtr>>,
363}
364
365pub struct VastStatementBlock {
366    inner: *mut sys::CVastStatementBlock,
367    parent: Arc<Mutex<VastFilePtr>>,
368}
369
370pub struct VastStatement {
371    inner: *mut sys::CVastStatement,
372    parent: Arc<Mutex<VastFilePtr>>,
373}
374
375pub struct Conditional {
376    inner: *mut sys::CVastConditional,
377    parent: Arc<Mutex<VastFilePtr>>,
378}
379
380pub struct CaseStatement {
381    inner: *mut sys::CVastCaseStatement,
382    parent: Arc<Mutex<VastFilePtr>>,
383}
384
385pub struct GenerateLoop {
386    inner: *mut sys::CVastGenerateLoop,
387    parent: Arc<Mutex<VastFilePtr>>,
388}
389
390pub struct ParameterRef {
391    inner: *mut sys::CVastParameterRef,
392    parent: Arc<Mutex<VastFilePtr>>,
393}
394
395pub struct LocalparamRef {
396    inner: *mut sys::CVastLocalparamRef,
397    parent: Arc<Mutex<VastFilePtr>>,
398}
399
400impl LocalparamRef {
401    pub fn to_expr(&self) -> Expr {
402        let locked = self.parent.lock().unwrap();
403        let inner = unsafe { sys::xls_vast_localparam_ref_as_expression(self.inner) };
404        Expr {
405            inner,
406            parent: self.parent.clone(),
407        }
408    }
409}
410pub struct Def {
411    inner: *mut sys::CVastDef,
412    parent: Arc<Mutex<VastFilePtr>>,
413}
414
415#[derive(Clone, Copy, Debug, PartialEq, Eq)]
416pub enum DataKind {
417    Reg,
418    Wire,
419    Logic,
420    Integer,
421    Int,
422    User,
423    UntypedEnum,
424    Genvar,
425}
426
427impl DataKind {
428    fn to_sys(self) -> i32 {
429        match self {
430            DataKind::Reg => sys::XLS_VAST_DATA_KIND_REG,
431            DataKind::Wire => sys::XLS_VAST_DATA_KIND_WIRE,
432            DataKind::Logic => sys::XLS_VAST_DATA_KIND_LOGIC,
433            DataKind::Integer => sys::XLS_VAST_DATA_KIND_INTEGER,
434            DataKind::Int => sys::XLS_VAST_DATA_KIND_INT,
435            DataKind::User => sys::XLS_VAST_DATA_KIND_USER,
436            DataKind::UntypedEnum => sys::XLS_VAST_DATA_KIND_UNTYPED_ENUM,
437            DataKind::Genvar => sys::XLS_VAST_DATA_KIND_GENVAR,
438        }
439    }
440}
441
442pub enum AlwaysKind {
443    AlwaysFF,
444    AlwaysAt,
445    AlwaysComb,
446}
447
448impl VastModule {
449    pub fn name(&self) -> String {
450        let locked = self.parent.lock().unwrap();
451        let inner = unsafe { sys::xls_vast_verilog_module_get_name(self.inner) };
452        unsafe { c_str_to_rust(inner) }
453    }
454
455    pub fn add_parameter_port(&mut self, name: &str, value: &Expr) -> LogicRef {
456        let c_name = CString::new(name).unwrap();
457        let _locked = self.parent.lock().unwrap();
458        let c_logic_ref = unsafe {
459            sys::xls_vast_verilog_module_add_parameter_port(
460                self.inner,
461                c_name.as_ptr(),
462                value.inner,
463            )
464        };
465        LogicRef {
466            inner: c_logic_ref,
467            parent: self.parent.clone(),
468        }
469    }
470
471    pub fn add_typed_parameter_port(
472        &mut self,
473        name: &str,
474        data_type: &VastDataType,
475        value: &Expr,
476    ) -> LogicRef {
477        let c_name = CString::new(name).unwrap();
478        let _locked = self.parent.lock().unwrap();
479        let c_logic_ref = unsafe {
480            sys::xls_vast_verilog_module_add_typed_parameter_port(
481                self.inner,
482                c_name.as_ptr(),
483                data_type.inner,
484                value.inner,
485            )
486        };
487        LogicRef {
488            inner: c_logic_ref,
489            parent: self.parent.clone(),
490        }
491    }
492
493    pub fn add_input(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
494        let c_name = CString::new(name).unwrap();
495        let _locked = self.parent.lock().unwrap();
496        let c_logic_ref = unsafe {
497            sys::xls_vast_verilog_module_add_input(self.inner, c_name.as_ptr(), data_type.inner)
498        };
499        LogicRef {
500            inner: c_logic_ref,
501            parent: self.parent.clone(),
502        }
503    }
504
505    pub fn add_output(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
506        let c_name = CString::new(name).unwrap();
507        let _locked = self.parent.lock().unwrap();
508        let c_logic_ref = unsafe {
509            sys::xls_vast_verilog_module_add_output(self.inner, c_name.as_ptr(), data_type.inner)
510        };
511        LogicRef {
512            inner: c_logic_ref,
513            parent: self.parent.clone(),
514        }
515    }
516
517    pub fn add_inout(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
518        let c_name = CString::new(name).unwrap();
519        let _locked = self.parent.lock().unwrap();
520        let c_logic_ref = unsafe {
521            sys::xls_vast_verilog_module_add_inout(self.inner, c_name.as_ptr(), data_type.inner)
522        };
523        LogicRef {
524            inner: c_logic_ref,
525            parent: self.parent.clone(),
526        }
527    }
528
529    pub fn add_logic_input(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
530        let c_name = CString::new(name).unwrap();
531        let _locked = self.parent.lock().unwrap();
532        let c_logic_ref = unsafe {
533            sys::xls_vast_verilog_module_add_logic_input(
534                self.inner,
535                c_name.as_ptr(),
536                data_type.inner,
537            )
538        };
539        LogicRef {
540            inner: c_logic_ref,
541            parent: self.parent.clone(),
542        }
543    }
544
545    pub fn add_logic_output(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
546        let c_name = CString::new(name).unwrap();
547        let _locked = self.parent.lock().unwrap();
548        let c_logic_ref = unsafe {
549            sys::xls_vast_verilog_module_add_logic_output(
550                self.inner,
551                c_name.as_ptr(),
552                data_type.inner,
553            )
554        };
555        LogicRef {
556            inner: c_logic_ref,
557            parent: self.parent.clone(),
558        }
559    }
560
561    pub fn add_wire(&mut self, name: &str, data_type: &VastDataType) -> LogicRef {
562        let c_name = CString::new(name).unwrap();
563        let _locked = self.parent.lock().unwrap();
564        let c_logic_ref = unsafe {
565            sys::xls_vast_verilog_module_add_wire(self.inner, c_name.as_ptr(), data_type.inner)
566        };
567        LogicRef {
568            inner: c_logic_ref,
569            parent: self.parent.clone(),
570        }
571    }
572
573    pub fn add_generate_loop(
574        &mut self,
575        genvar_name: &str,
576        init: &Expr,
577        limit: &Expr,
578        label: Option<&str>,
579    ) -> GenerateLoop {
580        let c_name = CString::new(genvar_name).unwrap();
581        let c_label =
582            CString::new(label.unwrap_or("")).expect("label should not contain NUL characters");
583        let _locked = self.parent.lock().unwrap();
584        let inner = unsafe {
585            sys::xls_vast_verilog_module_add_generate_loop(
586                self.inner,
587                c_name.as_ptr(),
588                init.inner,
589                limit.inner,
590                c_label.as_ptr(),
591            )
592        };
593        GenerateLoop {
594            inner,
595            parent: self.parent.clone(),
596        }
597    }
598
599    /// Adds a member to this module which is an instantiation of another module
600    /// -- this is described by the given `Instantiation` -- see
601    /// `VastFile::make_instantiation`.
602    pub fn add_member_instantiation(&mut self, instantiation: Instantiation) {
603        let _locked = self.parent.lock().unwrap();
604        unsafe {
605            sys::xls_vast_verilog_module_add_member_instantiation(self.inner, instantiation.inner)
606        }
607    }
608
609    /// Adds a "continuous assignment" member to this module; i.e. a statement
610    /// of the form: `assign <lhs> = <rhs>;`
611    ///
612    /// Create a `ContinuousAssignment` structure that describes the assignment
613    /// via `VastFile::make_continuous_assignment`.
614    pub fn add_member_continuous_assignment(&mut self, assignment: ContinuousAssignment) {
615        let _locked = self.parent.lock().unwrap();
616        unsafe {
617            sys::xls_vast_verilog_module_add_member_continuous_assignment(
618                self.inner,
619                assignment.inner,
620            )
621        }
622    }
623
624    pub fn add_member_blank_line(&mut self, blank: BlankLine) {
625        let _locked = self.parent.lock().unwrap();
626        unsafe { sys::xls_vast_verilog_module_add_member_blank_line(self.inner, blank.inner) }
627    }
628
629    pub fn add_member_comment(&mut self, comment: Comment) {
630        let _locked = self.parent.lock().unwrap();
631        unsafe { sys::xls_vast_verilog_module_add_member_comment(self.inner, comment.inner) }
632    }
633
634    pub fn add_member_inline_statement(&mut self, stmt: InlineVerilogStatement) {
635        let _locked = self.parent.lock().unwrap();
636        unsafe { sys::xls_vast_verilog_module_add_member_inline_statement(self.inner, stmt.inner) }
637    }
638
639    pub fn add_member_macro_statement(&mut self, stmt: MacroStatement) {
640        let _locked = self.parent.lock().unwrap();
641        unsafe { sys::xls_vast_verilog_module_add_member_macro_statement(self.inner, stmt.inner) }
642    }
643
644    pub fn add_conditional(&mut self, cond: &Expr) -> Conditional {
645        let _locked = self.parent.lock().unwrap();
646        let inner = unsafe { sys::xls_vast_verilog_module_add_conditional(self.inner, cond.inner) };
647        Conditional {
648            inner,
649            parent: self.parent.clone(),
650        }
651    }
652
653    pub fn add_reg(
654        &mut self,
655        name: &str,
656        data_type: &VastDataType,
657    ) -> Result<LogicRef, XlsynthError> {
658        let c_name = CString::new(name).unwrap();
659        let _locked = self.parent.lock().unwrap();
660        let mut reg_ref_out: *mut sys::CVastLogicRef = std::ptr::null_mut();
661        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
662        let success = unsafe {
663            sys::xls_vast_verilog_module_add_reg(
664                self.inner,
665                c_name.as_ptr(),
666                data_type.inner,
667                &mut reg_ref_out,
668                &mut error_out,
669            )
670        };
671        if success {
672            Ok(LogicRef {
673                inner: reg_ref_out,
674                parent: self.parent.clone(),
675            })
676        } else {
677            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
678        }
679    }
680
681    pub fn add_logic(
682        &mut self,
683        name: &str,
684        data_type: &VastDataType,
685    ) -> Result<LogicRef, XlsynthError> {
686        let c_name = CString::new(name).unwrap();
687        let _locked = self.parent.lock().unwrap();
688        let mut reg_ref_out: *mut sys::CVastLogicRef = std::ptr::null_mut();
689        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
690        let success = unsafe {
691            sys::xls_vast_verilog_module_add_logic(
692                self.inner,
693                c_name.as_ptr(),
694                data_type.inner,
695                &mut reg_ref_out,
696                &mut error_out,
697            )
698        };
699        if success {
700            Ok(LogicRef {
701                inner: reg_ref_out,
702                parent: self.parent.clone(),
703            })
704        } else {
705            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
706        }
707    }
708
709    fn add_always_block(
710        &mut self,
711        sensitivity_list: &[&Expr],
712        always_kind: AlwaysKind,
713    ) -> Result<VastAlwaysBase, XlsynthError> {
714        let _locked = self.parent.lock().unwrap();
715        let mut expr_ptrs: Vec<*mut sys::CVastExpression> =
716            sensitivity_list.iter().map(|expr| expr.inner).collect();
717        let mut always_base_out: *mut sys::CVastAlwaysBase = std::ptr::null_mut();
718        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
719        let success = unsafe {
720            match always_kind {
721                AlwaysKind::AlwaysFF => sys::xls_vast_verilog_module_add_always_ff(
722                    self.inner,
723                    expr_ptrs.as_mut_ptr(),
724                    expr_ptrs.len(),
725                    &mut always_base_out,
726                    &mut error_out,
727                ),
728                AlwaysKind::AlwaysAt => sys::xls_vast_verilog_module_add_always_at(
729                    self.inner,
730                    expr_ptrs.as_mut_ptr(),
731                    expr_ptrs.len(),
732                    &mut always_base_out,
733                    &mut error_out,
734                ),
735                AlwaysKind::AlwaysComb => sys::xls_vast_verilog_module_add_always_comb(
736                    self.inner,
737                    &mut always_base_out,
738                    &mut error_out,
739                ),
740            }
741        };
742        if success {
743            Ok(VastAlwaysBase {
744                inner: always_base_out,
745                parent: self.parent.clone(),
746            })
747        } else {
748            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
749        }
750    }
751
752    /// Note: this does not warn or error if you add it to a Verilog-based file.
753    pub fn add_always_ff(
754        &mut self,
755        sensitivity_list: &[&Expr],
756    ) -> Result<VastAlwaysBase, XlsynthError> {
757        self.add_always_block(sensitivity_list, AlwaysKind::AlwaysFF)
758    }
759
760    pub fn add_always_at(
761        &mut self,
762        sensitivity_list: &[&Expr],
763    ) -> Result<VastAlwaysBase, XlsynthError> {
764        self.add_always_block(sensitivity_list, AlwaysKind::AlwaysAt)
765    }
766
767    pub fn add_always_comb(&mut self) -> Result<VastAlwaysBase, XlsynthError> {
768        self.add_always_block(&[], AlwaysKind::AlwaysComb)
769    }
770
771    pub fn add_parameter(&mut self, name: &str, rhs: &Expr) -> ParameterRef {
772        let c_name = CString::new(name).unwrap();
773        let _locked = self.parent.lock().unwrap();
774        let inner = unsafe {
775            sys::xls_vast_verilog_module_add_parameter(self.inner, c_name.as_ptr(), rhs.inner)
776        };
777        ParameterRef {
778            inner,
779            parent: self.parent.clone(),
780        }
781    }
782
783    pub fn add_parameter_with_def(&mut self, def: &Def, rhs: &Expr) -> ParameterRef {
784        let _locked = self.parent.lock().unwrap();
785        let inner = unsafe {
786            sys::xls_vast_verilog_module_add_parameter_with_def(self.inner, def.inner, rhs.inner)
787        };
788        ParameterRef {
789            inner,
790            parent: self.parent.clone(),
791        }
792    }
793
794    pub fn add_localparam(&mut self, name: &str, rhs: &Expr) -> LocalparamRef {
795        let c_name = CString::new(name).unwrap();
796        let _locked = self.parent.lock().unwrap();
797        let inner = unsafe {
798            sys::xls_vast_verilog_module_add_localparam(self.inner, c_name.as_ptr(), rhs.inner)
799        };
800        LocalparamRef {
801            inner,
802            parent: self.parent.clone(),
803        }
804    }
805
806    pub fn add_typed_localparam(&mut self, def: &Def, rhs: &Expr) -> LocalparamRef {
807        let _locked = self.parent.lock().unwrap();
808        let inner = unsafe {
809            sys::xls_vast_verilog_module_add_localparam_with_def(self.inner, def.inner, rhs.inner)
810        };
811        LocalparamRef {
812            inner,
813            parent: self.parent.clone(),
814        }
815    }
816
817    /// Adds a localparam with SystemVerilog `int` type.
818    pub fn add_int_localparam(&mut self, name: &str, rhs: &Expr) -> LocalparamRef {
819        let c_name = CString::new(name).unwrap();
820        let locked = self.parent.lock().unwrap();
821        let int_def =
822            unsafe { sys::xls_vast_verilog_file_make_int_def(locked.0, c_name.as_ptr(), true) };
823        let inner = unsafe {
824            sys::xls_vast_verilog_module_add_localparam_with_def(self.inner, int_def, rhs.inner)
825        };
826        LocalparamRef {
827            inner,
828            parent: self.parent.clone(),
829        }
830    }
831}
832
833impl VastAlwaysBase {
834    pub fn get_statement_block(&self) -> VastStatementBlock {
835        let _locked = self.parent.lock().unwrap();
836        let inner = unsafe { sys::xls_vast_always_base_get_statement_block(self.inner) };
837        VastStatementBlock {
838            inner,
839            parent: self.parent.clone(),
840        }
841    }
842}
843
844impl VastStatementBlock {
845    pub fn add_blocking_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
846        let _locked = self.parent.lock().unwrap();
847        let inner = unsafe {
848            sys::xls_vast_statement_block_add_blocking_assignment(self.inner, lhs.inner, rhs.inner)
849        };
850        VastStatement {
851            inner,
852            parent: self.parent.clone(),
853        }
854    }
855
856    pub fn add_continuous_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
857        let _locked = self.parent.lock().unwrap();
858        let inner = unsafe {
859            sys::xls_vast_statement_block_add_continuous_assignment(
860                self.inner, lhs.inner, rhs.inner,
861            )
862        };
863        VastStatement {
864            inner,
865            parent: self.parent.clone(),
866        }
867    }
868
869    pub fn add_nonblocking_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
870        let _locked = self.parent.lock().unwrap();
871        let inner = unsafe {
872            sys::xls_vast_statement_block_add_nonblocking_assignment(
873                self.inner, lhs.inner, rhs.inner,
874            )
875        };
876        VastStatement {
877            inner,
878            parent: self.parent.clone(),
879        }
880    }
881
882    pub fn add_comment_text(&mut self, text: &str) -> VastStatement {
883        let c_text = CString::new(text).unwrap();
884        let _locked = self.parent.lock().unwrap();
885        let inner =
886            unsafe { sys::xls_vast_statement_block_add_comment_text(self.inner, c_text.as_ptr()) };
887        VastStatement {
888            inner,
889            parent: self.parent.clone(),
890        }
891    }
892
893    pub fn add_blank_line(&mut self) -> VastStatement {
894        let _locked = self.parent.lock().unwrap();
895        let inner = unsafe { sys::xls_vast_statement_block_add_blank_line(self.inner) };
896        VastStatement {
897            inner,
898            parent: self.parent.clone(),
899        }
900    }
901
902    pub fn add_inline_text(&mut self, text: &str) -> VastStatement {
903        let c_text = CString::new(text).unwrap();
904        let _locked = self.parent.lock().unwrap();
905        let inner =
906            unsafe { sys::xls_vast_statement_block_add_inline_text(self.inner, c_text.as_ptr()) };
907        VastStatement {
908            inner,
909            parent: self.parent.clone(),
910        }
911    }
912
913    pub fn add_cond(&mut self, cond: &Expr) -> Conditional {
914        let _locked = self.parent.lock().unwrap();
915        let inner =
916            unsafe { sys::xls_vast_statement_block_add_conditional(self.inner, cond.inner) };
917        Conditional {
918            inner,
919            parent: self.parent.clone(),
920        }
921    }
922
923    pub fn add_case(&mut self, selector: &Expr) -> CaseStatement {
924        let _locked = self.parent.lock().unwrap();
925        let inner = unsafe { sys::xls_vast_statement_block_add_case(self.inner, selector.inner) };
926        CaseStatement {
927            inner,
928            parent: self.parent.clone(),
929        }
930    }
931}
932
933impl Conditional {
934    pub fn then_block(&self) -> VastStatementBlock {
935        let _locked = self.parent.lock().unwrap();
936        let inner = unsafe { sys::xls_vast_conditional_get_then_block(self.inner) };
937        VastStatementBlock {
938            inner,
939            parent: self.parent.clone(),
940        }
941    }
942
943    pub fn add_else_if(&self, cond: &Expr) -> VastStatementBlock {
944        let _locked = self.parent.lock().unwrap();
945        let inner = unsafe { sys::xls_vast_conditional_add_else_if(self.inner, cond.inner) };
946        VastStatementBlock {
947            inner,
948            parent: self.parent.clone(),
949        }
950    }
951
952    pub fn add_else(&self) -> VastStatementBlock {
953        let _locked = self.parent.lock().unwrap();
954        let inner = unsafe { sys::xls_vast_conditional_add_else(self.inner) };
955        VastStatementBlock {
956            inner,
957            parent: self.parent.clone(),
958        }
959    }
960}
961
962impl CaseStatement {
963    pub fn add_item(&self, match_expr: &Expr) -> VastStatementBlock {
964        let _locked = self.parent.lock().unwrap();
965        let inner = unsafe { sys::xls_vast_case_statement_add_item(self.inner, match_expr.inner) };
966        VastStatementBlock {
967            inner,
968            parent: self.parent.clone(),
969        }
970    }
971
972    pub fn add_default(&self) -> VastStatementBlock {
973        let _locked = self.parent.lock().unwrap();
974        let inner = unsafe { sys::xls_vast_case_statement_add_default(self.inner) };
975        VastStatementBlock {
976            inner,
977            parent: self.parent.clone(),
978        }
979    }
980}
981
982impl GenerateLoop {
983    pub fn get_genvar(&self) -> LogicRef {
984        let _locked = self.parent.lock().unwrap();
985        let inner = unsafe { sys::xls_vast_generate_loop_get_genvar(self.inner) };
986        LogicRef {
987            inner,
988            parent: self.parent.clone(),
989        }
990    }
991
992    pub fn add_generate_loop(
993        &mut self,
994        genvar_name: &str,
995        init: &Expr,
996        limit: &Expr,
997        label: Option<&str>,
998    ) -> GenerateLoop {
999        let c_name = CString::new(genvar_name).unwrap();
1000        let c_label = CString::new(label.unwrap_or("")).unwrap();
1001        let _locked = self.parent.lock().unwrap();
1002        let inner = unsafe {
1003            sys::xls_vast_generate_loop_add_generate_loop(
1004                self.inner,
1005                c_name.as_ptr(),
1006                init.inner,
1007                limit.inner,
1008                c_label.as_ptr(),
1009            )
1010        };
1011        GenerateLoop {
1012            inner,
1013            parent: self.parent.clone(),
1014        }
1015    }
1016
1017    pub fn add_always_comb(&mut self) -> Result<VastAlwaysBase, XlsynthError> {
1018        let _locked = self.parent.lock().unwrap();
1019        let mut always_base_out: *mut sys::CVastAlwaysBase = std::ptr::null_mut();
1020        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1021        let success = unsafe {
1022            sys::xls_vast_generate_loop_add_always_comb(
1023                self.inner,
1024                &mut always_base_out,
1025                &mut error_out,
1026            )
1027        };
1028        if success {
1029            Ok(VastAlwaysBase {
1030                inner: always_base_out,
1031                parent: self.parent.clone(),
1032            })
1033        } else {
1034            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
1035        }
1036    }
1037
1038    pub fn add_always_ff(
1039        &mut self,
1040        sensitivity_list: &[&Expr],
1041    ) -> Result<VastAlwaysBase, XlsynthError> {
1042        let _locked = self.parent.lock().unwrap();
1043        let mut expr_ptrs: Vec<*mut sys::CVastExpression> =
1044            sensitivity_list.iter().map(|e| e.inner).collect();
1045        let mut always_base_out: *mut sys::CVastAlwaysBase = std::ptr::null_mut();
1046        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1047        let success = unsafe {
1048            sys::xls_vast_generate_loop_add_always_ff(
1049                self.inner,
1050                expr_ptrs.as_mut_ptr(),
1051                expr_ptrs.len(),
1052                &mut always_base_out,
1053                &mut error_out,
1054            )
1055        };
1056        if success {
1057            Ok(VastAlwaysBase {
1058                inner: always_base_out,
1059                parent: self.parent.clone(),
1060            })
1061        } else {
1062            Err(XlsynthError(unsafe { c_str_to_rust(error_out) }))
1063        }
1064    }
1065
1066    pub fn add_localparam(&mut self, name: &str, rhs: &Expr) -> LocalparamRef {
1067        let c_name = CString::new(name).unwrap();
1068        let _locked = self.parent.lock().unwrap();
1069        let inner = unsafe {
1070            sys::xls_vast_generate_loop_add_localparam(self.inner, c_name.as_ptr(), rhs.inner)
1071        };
1072        LocalparamRef {
1073            inner,
1074            parent: self.parent.clone(),
1075        }
1076    }
1077
1078    pub fn add_typed_localparam(&mut self, def: &Def, rhs: &Expr) -> LocalparamRef {
1079        let _locked = self.parent.lock().unwrap();
1080        let inner = unsafe {
1081            sys::xls_vast_generate_loop_add_localparam_with_def(self.inner, def.inner, rhs.inner)
1082        };
1083        LocalparamRef {
1084            inner,
1085            parent: self.parent.clone(),
1086        }
1087    }
1088
1089    pub fn add_continuous_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
1090        let _locked = self.parent.lock().unwrap();
1091        let inner = unsafe {
1092            sys::xls_vast_generate_loop_add_continuous_assignment(self.inner, lhs.inner, rhs.inner)
1093        };
1094        VastStatement {
1095            inner,
1096            parent: self.parent.clone(),
1097        }
1098    }
1099
1100    pub fn add_conditional(&mut self, cond: &Expr) -> Conditional {
1101        let _locked = self.parent.lock().unwrap();
1102        let inner = unsafe { sys::xls_vast_generate_loop_add_conditional(self.inner, cond.inner) };
1103        Conditional {
1104            inner,
1105            parent: self.parent.clone(),
1106        }
1107    }
1108
1109    pub fn add_blank_line(&mut self) {
1110        let _locked = self.parent.lock().unwrap();
1111        unsafe { sys::xls_vast_generate_loop_add_blank_line(self.inner) }
1112    }
1113
1114    pub fn add_comment(&mut self, comment: &Comment) {
1115        let _locked = self.parent.lock().unwrap();
1116        unsafe { sys::xls_vast_generate_loop_add_comment(self.inner, comment.inner) }
1117    }
1118
1119    pub fn add_instantiation(&mut self, inst: &Instantiation) {
1120        let _locked = self.parent.lock().unwrap();
1121        unsafe { sys::xls_vast_generate_loop_add_instantiation(self.inner, inst.inner) }
1122    }
1123
1124    pub fn add_inline_statement(&mut self, stmt: &InlineVerilogStatement) {
1125        let _locked = self.parent.lock().unwrap();
1126        unsafe { sys::xls_vast_generate_loop_add_inline_verilog_statement(self.inner, stmt.inner) }
1127    }
1128
1129    pub fn add_macro_statement(&mut self, macro_statement: &MacroStatement) {
1130        let _locked = self.parent.lock().unwrap();
1131        unsafe {
1132            sys::xls_vast_generate_loop_add_macro_statement(self.inner, macro_statement.inner)
1133        }
1134    }
1135}
1136
1137pub enum VastFileType {
1138    Verilog,
1139    SystemVerilog,
1140}
1141
1142pub struct VastFile {
1143    ptr: Arc<Mutex<VastFilePtr>>,
1144}
1145
1146impl VastFile {
1147    /// Create a new VAST file.
1148    pub fn new(file_type: VastFileType) -> Self {
1149        let c_file_type = match file_type {
1150            VastFileType::Verilog => 0,
1151            VastFileType::SystemVerilog => 1,
1152        };
1153        Self {
1154            ptr: Arc::new(Mutex::new(VastFilePtr(unsafe {
1155                sys::xls_vast_make_verilog_file(c_file_type)
1156            }))),
1157        }
1158    }
1159
1160    /// Adds a tick-include to the file.
1161    pub fn add_include(&mut self, include: &str) {
1162        let c_include = CString::new(include).unwrap();
1163        let locked = self.ptr.lock().unwrap();
1164        unsafe { sys::xls_vast_verilog_file_add_include(locked.0, c_include.as_ptr()) }
1165    }
1166
1167    /// Adds a file-level blank line.
1168    pub fn add_blank_line(&mut self, blank_line: BlankLine) {
1169        let locked = self.ptr.lock().unwrap();
1170        unsafe { sys::xls_vast_verilog_file_add_blank_line(locked.0, blank_line.inner) }
1171    }
1172
1173    /// Adds a file-level `// ...` style comment from text.
1174    pub fn add_comment_text(&mut self, text: &str) {
1175        let c_text = CString::new(text).unwrap();
1176        let locked = self.ptr.lock().unwrap();
1177        unsafe { sys::xls_vast_verilog_file_add_comment(locked.0, c_text.as_ptr()) }
1178    }
1179
1180    pub fn add_module(&mut self, name: &str) -> VastModule {
1181        let c_name = CString::new(name).unwrap();
1182        let locked = self.ptr.lock().unwrap();
1183        let module = unsafe { sys::xls_vast_verilog_file_add_module(locked.0, c_name.as_ptr()) };
1184        VastModule {
1185            inner: module,
1186            parent: self.ptr.clone(),
1187        }
1188    }
1189
1190    /// Creates a structure that describes an instantiation of a module that we
1191    /// want to create (as a member within some module, see
1192    /// `VastModule::add_member_instantiation`).
1193    ///
1194    /// Args:
1195    /// - `module_name`: The name of the module to instantiate.
1196    /// - `instance_name`: The name of the instance of the module to create.
1197    /// - `parameter_port_names`: The names of the `parameter`s of the module to
1198    ///   instantiate.
1199    /// - `parameter_expressions`: The expressions to use in instantiating the
1200    ///   parameters of the module.
1201    /// - `connection_port_names`: The names of the ports of the module to
1202    ///   instantiate.
1203    /// - `connection_expressions`: The expressions to use in instantiating the
1204    ///   ports of the module.
1205    pub fn make_instantiation(
1206        &mut self,
1207        module_name: &str,
1208        instance_name: &str,
1209        parameter_port_names: &[&str],
1210        parameter_expressions: &[&Expr],
1211        connection_port_names: &[&str],
1212        connection_expressions: &[Option<&Expr>],
1213    ) -> Instantiation {
1214        let c_module_name = CString::new(module_name).unwrap();
1215        let c_instance_name = CString::new(instance_name).unwrap();
1216
1217        // Even though we only need char pointers to call the C++ API, we need to return
1218        // a Vec of CStrings in addition to the char pointers, to prevent the strings
1219        // from being dropped before the pointers are used.
1220        fn to_cstrings_and_ptrs(strings: &[&str]) -> (Vec<CString>, Vec<*const c_char>) {
1221            let cstrings: Vec<CString> =
1222                strings.iter().map(|&s| CString::new(s).unwrap()).collect();
1223            let ptrs = cstrings.iter().map(|s| s.as_ptr()).collect();
1224            (cstrings, ptrs)
1225        }
1226
1227        let (c_param_names, c_param_name_ptrs) = to_cstrings_and_ptrs(parameter_port_names);
1228        let (c_conn_names, c_conn_name_ptrs) = to_cstrings_and_ptrs(connection_port_names);
1229
1230        fn to_expr_ptrs(exprs: &[&Expr]) -> Vec<*const sys::CVastExpression> {
1231            exprs
1232                .iter()
1233                .map(|expr| expr.inner as *const sys::CVastExpression)
1234                .collect()
1235        }
1236
1237        fn to_opt_expr_ptrs(exprs: &[Option<&Expr>]) -> Vec<*const sys::CVastExpression> {
1238            exprs
1239                .iter()
1240                .map(|expr| {
1241                    if let Some(expr) = expr {
1242                        expr.inner as *const sys::CVastExpression
1243                    } else {
1244                        std::ptr::null()
1245                    }
1246                })
1247                .collect()
1248        }
1249
1250        let c_param_expr_ptrs = to_expr_ptrs(parameter_expressions);
1251        let c_conn_expr_ptrs = to_opt_expr_ptrs(connection_expressions);
1252
1253        let locked = self.ptr.lock().unwrap();
1254
1255        let instantiation = unsafe {
1256            sys::xls_vast_verilog_file_make_instantiation(
1257                locked.0,
1258                c_module_name.as_ptr(),
1259                c_instance_name.as_ptr(),
1260                c_param_name_ptrs.as_ptr(),
1261                c_param_expr_ptrs.as_ptr(),
1262                c_param_expr_ptrs.len(),
1263                c_conn_name_ptrs.as_ptr(),
1264                c_conn_expr_ptrs.as_ptr(),
1265                c_conn_expr_ptrs.len(),
1266            )
1267        };
1268
1269        Instantiation {
1270            inner: instantiation,
1271            parent: self.ptr.clone(),
1272        }
1273    }
1274
1275    /// Makes a literal expression from a string, `s`, using the given format,
1276    /// `fmt`. `s` must be in the form `bits[N]:value`, where `N` is the bit
1277    /// width and `value` is the value of the literal, expressed in decimal,
1278    /// hex, or binary. For example, `s` might be `bits[16]:42` or
1279    /// `bits[39]:0xABCD`. `fmt` indicates how the literal should be formatted
1280    /// in the output Verilog.
1281    pub fn make_literal(
1282        &mut self,
1283        s: &str,
1284        fmt: &IrFormatPreference,
1285    ) -> Result<Expr, XlsynthError> {
1286        let v = xls_parse_typed_value(s).unwrap();
1287        let mut fmt = xls_format_preference_from_string(fmt.to_string()).unwrap();
1288
1289        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1290        let mut literal_out: *mut sys::CVastLiteral = std::ptr::null_mut();
1291
1292        unsafe {
1293            let success = sys::xls_vast_verilog_file_make_literal(
1294                self.ptr.lock().unwrap().0,
1295                v.to_bits().unwrap().ptr,
1296                fmt,
1297                true,
1298                &mut error_out,
1299                &mut literal_out,
1300            );
1301
1302            if success {
1303                Ok(Expr {
1304                    inner: sys::xls_vast_literal_as_expression(literal_out),
1305                    parent: self.ptr.clone(),
1306                })
1307            } else {
1308                Err(XlsynthError(c_str_to_rust(error_out)))
1309            }
1310        }
1311    }
1312    pub fn make_plain_literal(&mut self, value: i32, fmt: &IrFormatPreference) -> Expr {
1313        let mut error_out: *mut std::os::raw::c_char = std::ptr::null_mut();
1314        let mut literal_out: *mut sys::CVastLiteral = std::ptr::null_mut();
1315        let literal = unsafe {
1316            sys::xls_vast_verilog_file_make_plain_literal(self.ptr.lock().unwrap().0, value)
1317        };
1318        Expr {
1319            inner: unsafe { sys::xls_vast_literal_as_expression(literal) },
1320            parent: self.ptr.clone(),
1321        }
1322    }
1323
1324    pub fn make_comment(&mut self, text: &str) -> Comment {
1325        let locked = self.ptr.lock().unwrap();
1326        let c_text = CString::new(text).unwrap();
1327        let inner = unsafe { sys::xls_vast_verilog_file_make_comment(locked.0, c_text.as_ptr()) };
1328        Comment {
1329            inner,
1330            parent: self.ptr.clone(),
1331        }
1332    }
1333
1334    pub fn make_scalar_type(&mut self) -> VastDataType {
1335        let locked = self.ptr.lock().unwrap();
1336        let data_type = unsafe { sys::xls_vast_verilog_file_make_scalar_type(locked.0) };
1337        VastDataType {
1338            inner: data_type,
1339            parent: self.ptr.clone(),
1340        }
1341    }
1342
1343    pub fn make_bit_vector_type(&mut self, bit_count: i64, is_signed: bool) -> VastDataType {
1344        let locked = self.ptr.lock().unwrap();
1345        let data_type = unsafe {
1346            sys::xls_vast_verilog_file_make_bit_vector_type(locked.0, bit_count, is_signed)
1347        };
1348        VastDataType {
1349            inner: data_type,
1350            parent: self.ptr.clone(),
1351        }
1352    }
1353
1354    /// Creates a bit-vector type with an expression-based width.
1355    /// The emitted range will be [width_expr-1:0].
1356    pub fn make_bit_vector_type_expr(
1357        &mut self,
1358        width_expr: &Expr,
1359        is_signed: bool,
1360    ) -> VastDataType {
1361        let locked = self.ptr.lock().unwrap();
1362        let data_type = unsafe {
1363            sys::xls_vast_verilog_file_make_bit_vector_type_with_expression(
1364                locked.0,
1365                width_expr.inner,
1366                is_signed,
1367            )
1368        };
1369        VastDataType {
1370            inner: data_type,
1371            parent: self.ptr.clone(),
1372        }
1373    }
1374
1375    pub fn make_extern_type(&mut self, entity_name: &str) -> VastDataType {
1376        let locked = self.ptr.lock().unwrap();
1377        let c_entity_name = CString::new(entity_name).unwrap();
1378        let data_type = unsafe {
1379            sys::xls_vast_verilog_file_make_extern_type(locked.0, c_entity_name.as_ptr())
1380        };
1381        VastDataType {
1382            inner: data_type,
1383            parent: self.ptr.clone(),
1384        }
1385    }
1386
1387    pub fn make_extern_package_type(
1388        &mut self,
1389        package_name: &str,
1390        type_name: &str,
1391    ) -> VastDataType {
1392        let locked = self.ptr.lock().unwrap();
1393        let c_package_name = CString::new(package_name).unwrap();
1394        let c_type_name = CString::new(type_name).unwrap();
1395        let data_type = unsafe {
1396            sys::xls_vast_verilog_file_make_extern_package_type(
1397                locked.0,
1398                c_package_name.as_ptr(),
1399                c_type_name.as_ptr(),
1400            )
1401        };
1402        VastDataType {
1403            inner: data_type,
1404            parent: self.ptr.clone(),
1405        }
1406    }
1407
1408    pub fn make_integer_type(&mut self, is_signed: bool) -> VastDataType {
1409        let locked = self.ptr.lock().unwrap();
1410        let data_type =
1411            unsafe { sys::xls_vast_verilog_file_make_integer_type(locked.0, is_signed) };
1412        VastDataType {
1413            inner: data_type,
1414            parent: self.ptr.clone(),
1415        }
1416    }
1417
1418    pub fn make_int_type(&mut self, is_signed: bool) -> VastDataType {
1419        let locked = self.ptr.lock().unwrap();
1420        let data_type = unsafe { sys::xls_vast_verilog_file_make_int_type(locked.0, is_signed) };
1421        VastDataType {
1422            inner: data_type,
1423            parent: self.ptr.clone(),
1424        }
1425    }
1426
1427    pub fn make_packed_array_type(
1428        &mut self,
1429        element_type: VastDataType,
1430        dimensions: &[i64],
1431    ) -> VastDataType {
1432        let locked = self.ptr.lock().unwrap();
1433        let data_type = unsafe {
1434            sys::xls_vast_verilog_file_make_packed_array_type(
1435                locked.0,
1436                element_type.inner,
1437                dimensions.as_ptr(),
1438                dimensions.len(),
1439            )
1440        };
1441        VastDataType {
1442            inner: data_type,
1443            parent: self.ptr.clone(),
1444        }
1445    }
1446
1447    pub fn make_unpacked_array_type(
1448        &mut self,
1449        element_type: VastDataType,
1450        dimensions: &[i64],
1451    ) -> VastDataType {
1452        let locked = self.ptr.lock().unwrap();
1453        let data_type = unsafe {
1454            sys::xls_vast_verilog_file_make_unpacked_array_type(
1455                locked.0,
1456                element_type.inner,
1457                dimensions.as_ptr(),
1458                dimensions.len(),
1459            )
1460        };
1461        VastDataType {
1462            inner: data_type,
1463            parent: self.ptr.clone(),
1464        }
1465    }
1466
1467    pub fn make_slice(&mut self, indexable: &IndexableExpr, hi: i64, lo: i64) -> Slice {
1468        let locked = self.ptr.lock().unwrap();
1469        let inner =
1470            unsafe { sys::xls_vast_verilog_file_make_slice_i64(locked.0, indexable.inner, hi, lo) };
1471        Slice {
1472            inner,
1473            parent: self.ptr.clone(),
1474        }
1475    }
1476
1477    pub fn make_slice_expr(&mut self, indexable: &IndexableExpr, hi: &Expr, lo: &Expr) -> Slice {
1478        let locked = self.ptr.lock().unwrap();
1479        let inner = unsafe {
1480            sys::xls_vast_verilog_file_make_slice(locked.0, indexable.inner, hi.inner, lo.inner)
1481        };
1482        Slice {
1483            inner,
1484            parent: self.ptr.clone(),
1485        }
1486    }
1487
1488    pub fn make_index(&mut self, indexable: &IndexableExpr, index: i64) -> Index {
1489        let locked = self.ptr.lock().unwrap();
1490        let inner =
1491            unsafe { sys::xls_vast_verilog_file_make_index_i64(locked.0, indexable.inner, index) };
1492        Index {
1493            inner,
1494            parent: self.ptr.clone(),
1495        }
1496    }
1497
1498    pub fn make_index_expr(&mut self, indexable: &IndexableExpr, index: &Expr) -> Index {
1499        let locked = self.ptr.lock().unwrap();
1500        let inner = unsafe {
1501            sys::xls_vast_verilog_file_make_index(locked.0, indexable.inner, index.inner)
1502        };
1503        Index {
1504            inner,
1505            parent: self.ptr.clone(),
1506        }
1507    }
1508
1509    pub fn make_concat(&mut self, exprs: &[&Expr]) -> Expr {
1510        let locked = self.ptr.lock().unwrap();
1511        let mut expr_ptrs: Vec<*mut sys::CVastExpression> =
1512            exprs.iter().map(|expr| expr.inner).collect();
1513        let inner = unsafe {
1514            sys::xls_vast_verilog_file_make_concat(locked.0, expr_ptrs.as_mut_ptr(), exprs.len())
1515        };
1516        Expr {
1517            inner,
1518            parent: self.ptr.clone(),
1519        }
1520    }
1521
1522    pub fn make_replicated_concat(&mut self, replication: &Expr, elements: &[&Expr]) -> Expr {
1523        let locked = self.ptr.lock().unwrap();
1524        let mut elem_ptrs: Vec<*mut sys::CVastExpression> =
1525            elements.iter().map(|e| e.inner).collect();
1526        let concat_ptr = unsafe {
1527            sys::xls_vast_verilog_file_make_replicated_concat(
1528                locked.0,
1529                replication.inner,
1530                elem_ptrs.as_mut_ptr(),
1531                elem_ptrs.len(),
1532            )
1533        };
1534        let inner = unsafe { sys::xls_vast_concat_as_expression(concat_ptr) };
1535        Expr {
1536            inner,
1537            parent: self.ptr.clone(),
1538        }
1539    }
1540
1541    pub fn make_replicated_concat_i64(
1542        &mut self,
1543        replication_count: i64,
1544        elements: &[&Expr],
1545    ) -> Expr {
1546        let locked = self.ptr.lock().unwrap();
1547        let mut elem_ptrs: Vec<*mut sys::CVastExpression> =
1548            elements.iter().map(|e| e.inner).collect();
1549        let concat_ptr = unsafe {
1550            sys::xls_vast_verilog_file_make_replicated_concat_i64(
1551                locked.0,
1552                replication_count,
1553                elem_ptrs.as_mut_ptr(),
1554                elem_ptrs.len(),
1555            )
1556        };
1557        let inner = unsafe { sys::xls_vast_concat_as_expression(concat_ptr) };
1558        Expr {
1559            inner,
1560            parent: self.ptr.clone(),
1561        }
1562    }
1563
1564    pub fn make_array_assignment_pattern(&mut self, elements: &[&Expr]) -> Expr {
1565        let locked = self.ptr.lock().unwrap();
1566        let mut element_ptrs: Vec<*mut sys::CVastExpression> =
1567            elements.iter().map(|e| e.inner).collect();
1568        let inner = unsafe {
1569            sys::xls_vast_verilog_file_make_array_assignment_pattern(
1570                locked.0,
1571                element_ptrs.as_mut_ptr(),
1572                element_ptrs.len(),
1573            )
1574        };
1575        Expr {
1576            inner,
1577            parent: self.ptr.clone(),
1578        }
1579    }
1580
1581    pub fn make_macro_ref(&mut self, name: &str) -> MacroRef {
1582        let locked = self.ptr.lock().unwrap();
1583        let c_name = CString::new(name).unwrap();
1584        let inner = unsafe { sys::xls_vast_verilog_file_make_macro_ref(locked.0, c_name.as_ptr()) };
1585        MacroRef {
1586            inner,
1587            parent: self.ptr.clone(),
1588        }
1589    }
1590
1591    pub fn make_macro_ref_with_args(&mut self, name: &str, args: &[&Expr]) -> MacroRef {
1592        let locked = self.ptr.lock().unwrap();
1593        let c_name = CString::new(name).unwrap();
1594        let mut arg_ptrs: Vec<*mut sys::CVastExpression> = args.iter().map(|e| e.inner).collect();
1595        let inner = unsafe {
1596            sys::xls_vast_verilog_file_make_macro_ref_with_args(
1597                locked.0,
1598                c_name.as_ptr(),
1599                arg_ptrs.as_mut_ptr(),
1600                arg_ptrs.len(),
1601            )
1602        };
1603        MacroRef {
1604            inner,
1605            parent: self.ptr.clone(),
1606        }
1607    }
1608
1609    pub fn make_macro_statement(
1610        &mut self,
1611        macro_ref: &MacroRef,
1612        emit_semicolon: bool,
1613    ) -> MacroStatement {
1614        let locked = self.ptr.lock().unwrap();
1615        let inner = unsafe {
1616            sys::xls_vast_verilog_file_make_macro_statement(
1617                locked.0,
1618                macro_ref.inner,
1619                emit_semicolon,
1620            )
1621        };
1622        MacroStatement {
1623            inner,
1624            parent: self.ptr.clone(),
1625        }
1626    }
1627
1628    fn make_unary(&mut self, op: VastOperatorKind, expr: &Expr) -> Expr {
1629        let locked = self.ptr.lock().unwrap();
1630        let op_i32 = op as i32;
1631        let inner = unsafe { sys::xls_vast_verilog_file_make_unary(locked.0, expr.inner, op_i32) };
1632        Expr {
1633            inner,
1634            parent: self.ptr.clone(),
1635        }
1636    }
1637
1638    pub fn make_not(&mut self, expr: &Expr) -> Expr {
1639        self.make_unary(VastOperatorKind::BitwiseNot, expr)
1640    }
1641
1642    pub fn make_negate(&mut self, expr: &Expr) -> Expr {
1643        self.make_unary(VastOperatorKind::Negate, expr)
1644    }
1645
1646    pub fn make_logical_not(&mut self, expr: &Expr) -> Expr {
1647        self.make_unary(VastOperatorKind::LogicalNot, expr)
1648    }
1649
1650    pub fn make_and_reduce(&mut self, expr: &Expr) -> Expr {
1651        self.make_unary(VastOperatorKind::AndReduce, expr)
1652    }
1653
1654    pub fn make_or_reduce(&mut self, expr: &Expr) -> Expr {
1655        self.make_unary(VastOperatorKind::OrReduce, expr)
1656    }
1657
1658    pub fn make_xor_reduce(&mut self, expr: &Expr) -> Expr {
1659        self.make_unary(VastOperatorKind::XorReduce, expr)
1660    }
1661
1662    // -- binary ops
1663
1664    /// Internal helper for binary operators, users should prefer the
1665    /// `VastFile::make_*` methods below, such as `VastFile::make_add`.
1666    fn make_binary(&mut self, op: VastOperatorKind, lhs: &Expr, rhs: &Expr) -> Expr {
1667        let locked = self.ptr.lock().unwrap();
1668        let op_i32 = op as i32;
1669        let inner = unsafe {
1670            sys::xls_vast_verilog_file_make_binary(locked.0, lhs.inner, rhs.inner, op_i32)
1671        };
1672        Expr {
1673            inner,
1674            parent: self.ptr.clone(),
1675        }
1676    }
1677
1678    pub fn make_add(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1679        self.make_binary(VastOperatorKind::Add, lhs, rhs)
1680    }
1681
1682    pub fn make_sub(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1683        self.make_binary(VastOperatorKind::Sub, lhs, rhs)
1684    }
1685
1686    pub fn make_mul(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1687        self.make_binary(VastOperatorKind::Mul, lhs, rhs)
1688    }
1689
1690    pub fn make_div(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1691        self.make_binary(VastOperatorKind::Div, lhs, rhs)
1692    }
1693
1694    pub fn make_mod(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1695        self.make_binary(VastOperatorKind::Mod, lhs, rhs)
1696    }
1697
1698    pub fn make_power(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1699        self.make_binary(VastOperatorKind::Power, lhs, rhs)
1700    }
1701
1702    pub fn make_bitwise_and(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1703        self.make_binary(VastOperatorKind::BitwiseAnd, lhs, rhs)
1704    }
1705
1706    pub fn make_bitwise_or(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1707        self.make_binary(VastOperatorKind::BitwiseOr, lhs, rhs)
1708    }
1709
1710    pub fn make_bitwise_xor(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1711        self.make_binary(VastOperatorKind::BitwiseXor, lhs, rhs)
1712    }
1713
1714    pub fn make_bitwise_not(&mut self, expr: &Expr) -> Expr {
1715        self.make_unary(VastOperatorKind::BitwiseNot, expr)
1716    }
1717
1718    pub fn make_shll(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1719        self.make_binary(VastOperatorKind::Shll, lhs, rhs)
1720    }
1721
1722    pub fn make_shra(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1723        self.make_binary(VastOperatorKind::Shra, lhs, rhs)
1724    }
1725
1726    pub fn make_shrl(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1727        self.make_binary(VastOperatorKind::Shrl, lhs, rhs)
1728    }
1729
1730    pub fn make_ne(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1731        self.make_binary(VastOperatorKind::Ne, lhs, rhs)
1732    }
1733
1734    pub fn make_case_ne(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1735        self.make_binary(VastOperatorKind::CaseNe, lhs, rhs)
1736    }
1737
1738    pub fn make_eq(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1739        self.make_binary(VastOperatorKind::Eq, lhs, rhs)
1740    }
1741
1742    pub fn make_case_eq(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1743        self.make_binary(VastOperatorKind::CaseEq, lhs, rhs)
1744    }
1745
1746    pub fn make_ge(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1747        self.make_binary(VastOperatorKind::Ge, lhs, rhs)
1748    }
1749
1750    pub fn make_gt(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1751        self.make_binary(VastOperatorKind::Gt, lhs, rhs)
1752    }
1753
1754    pub fn make_le(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1755        self.make_binary(VastOperatorKind::Le, lhs, rhs)
1756    }
1757
1758    pub fn make_lt(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1759        self.make_binary(VastOperatorKind::Lt, lhs, rhs)
1760    }
1761
1762    pub fn make_logical_and(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1763        self.make_binary(VastOperatorKind::LogicalAnd, lhs, rhs)
1764    }
1765
1766    pub fn make_logical_or(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1767        self.make_binary(VastOperatorKind::LogicalOr, lhs, rhs)
1768    }
1769
1770    pub fn make_ne_x(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1771        self.make_binary(VastOperatorKind::NeX, lhs, rhs)
1772    }
1773
1774    pub fn make_eq_x(&mut self, lhs: &Expr, rhs: &Expr) -> Expr {
1775        self.make_binary(VastOperatorKind::EqX, lhs, rhs)
1776    }
1777
1778    // Creates a ternary operator that selects between `then_expr` and `else_expr`
1779    // based on the value of `cond`.
1780    pub fn make_ternary(&mut self, cond: &Expr, then_expr: &Expr, else_expr: &Expr) -> Expr {
1781        let locked = self.ptr.lock().unwrap();
1782        let inner = unsafe {
1783            sys::xls_vast_verilog_file_make_ternary(
1784                locked.0,
1785                cond.inner,
1786                then_expr.inner,
1787                else_expr.inner,
1788            )
1789        };
1790        Expr {
1791            inner,
1792            parent: self.ptr.clone(),
1793        }
1794    }
1795
1796    pub fn make_width_cast(&mut self, width: &Expr, value: &Expr) -> Expr {
1797        let locked = self.ptr.lock().unwrap();
1798        let inner = unsafe {
1799            sys::xls_vast_verilog_file_make_width_cast(locked.0, width.inner, value.inner)
1800        };
1801        Expr {
1802            inner,
1803            parent: self.ptr.clone(),
1804        }
1805    }
1806
1807    pub fn make_type_cast(&mut self, data_type: &VastDataType, value: &Expr) -> Expr {
1808        let locked = self.ptr.lock().unwrap();
1809        let inner = unsafe {
1810            sys::xls_vast_verilog_file_make_type_cast(locked.0, data_type.inner, value.inner)
1811        };
1812        Expr {
1813            inner,
1814            parent: self.ptr.clone(),
1815        }
1816    }
1817
1818    // Creates an `assign` statement that drives `lhs` with the `rhs` expression
1819    // given.
1820    pub fn make_continuous_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> ContinuousAssignment {
1821        let locked = self.ptr.lock().unwrap();
1822        let inner = unsafe {
1823            sys::xls_vast_verilog_file_make_continuous_assignment(locked.0, lhs.inner, rhs.inner)
1824        };
1825        ContinuousAssignment {
1826            inner,
1827            parent: self.ptr.clone(),
1828        }
1829    }
1830
1831    pub fn make_pos_edge(&mut self, expr: &Expr) -> Expr {
1832        let locked = self.ptr.lock().unwrap();
1833        let inner = unsafe { sys::xls_vast_verilog_file_make_pos_edge(locked.0, expr.inner) };
1834        Expr {
1835            inner,
1836            parent: self.ptr.clone(),
1837        }
1838    }
1839
1840    pub fn make_nonblocking_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
1841        let locked = self.ptr.lock().unwrap();
1842        let inner = unsafe {
1843            sys::xls_vast_verilog_file_make_nonblocking_assignment(locked.0, lhs.inner, rhs.inner)
1844        };
1845        VastStatement {
1846            inner,
1847            parent: self.ptr.clone(),
1848        }
1849    }
1850
1851    pub fn make_blocking_assignment(&mut self, lhs: &Expr, rhs: &Expr) -> VastStatement {
1852        let locked = self.ptr.lock().unwrap();
1853        let inner = unsafe {
1854            sys::xls_vast_verilog_file_make_blocking_assignment(locked.0, lhs.inner, rhs.inner)
1855        };
1856        VastStatement {
1857            inner,
1858            parent: self.ptr.clone(),
1859        }
1860    }
1861
1862    pub fn make_blank_line(&mut self) -> BlankLine {
1863        let locked = self.ptr.lock().unwrap();
1864        let inner = unsafe { sys::xls_vast_verilog_file_make_blank_line(locked.0) };
1865        BlankLine {
1866            inner,
1867            parent: self.ptr.clone(),
1868        }
1869    }
1870
1871    pub fn make_inline_verilog_statement(&mut self, text: &str) -> InlineVerilogStatement {
1872        let c_text = CString::new(text).unwrap();
1873        let locked = self.ptr.lock().unwrap();
1874        let inner = unsafe {
1875            sys::xls_vast_verilog_file_make_inline_verilog_statement(locked.0, c_text.as_ptr())
1876        };
1877        InlineVerilogStatement {
1878            inner,
1879            parent: self.ptr.clone(),
1880        }
1881    }
1882
1883    // Make a '1 literal.
1884    pub fn make_unsized_one_literal(&mut self) -> Expr {
1885        let locked = self.ptr.lock().unwrap();
1886        let inner = unsafe { sys::xls_vast_verilog_file_make_unsized_one_literal(locked.0) };
1887        Expr {
1888            inner,
1889            parent: self.ptr.clone(),
1890        }
1891    }
1892
1893    // Make a '0 literal.
1894    pub fn make_unsized_zero_literal(&mut self) -> Expr {
1895        let locked = self.ptr.lock().unwrap();
1896        let inner = unsafe { sys::xls_vast_verilog_file_make_unsized_zero_literal(locked.0) };
1897        Expr {
1898            inner,
1899            parent: self.ptr.clone(),
1900        }
1901    }
1902
1903    // Make an 'X literal.
1904    pub fn make_unsized_x_literal(&mut self) -> Expr {
1905        let locked = self.ptr.lock().unwrap();
1906        let inner = unsafe { sys::xls_vast_verilog_file_make_unsized_x_literal(locked.0) };
1907        Expr {
1908            inner,
1909            parent: self.ptr.clone(),
1910        }
1911    }
1912
1913    pub fn make_def(&mut self, name: &str, kind: DataKind, ty: &VastDataType) -> Def {
1914        let c_name = CString::new(name).unwrap();
1915        let locked = self.ptr.lock().unwrap();
1916        let inner = unsafe {
1917            sys::xls_vast_verilog_file_make_def(locked.0, c_name.as_ptr(), kind.to_sys(), ty.inner)
1918        };
1919        Def {
1920            inner,
1921            parent: self.ptr.clone(),
1922        }
1923    }
1924
1925    pub fn emit(&self) -> String {
1926        let locked = self.ptr.lock().unwrap();
1927        let c_str = unsafe { sys::xls_vast_verilog_file_emit(locked.0) };
1928        unsafe { c_str_to_rust(c_str) }
1929    }
1930}
1931
1932impl ParameterRef {
1933    pub fn to_expr(&self) -> Expr {
1934        let _locked = self.parent.lock().unwrap();
1935        let inner = unsafe { sys::xls_vast_parameter_ref_as_expression(self.inner) };
1936        Expr {
1937            inner,
1938            parent: self.parent.clone(),
1939        }
1940    }
1941
1942    pub fn to_indexable_expr(&self) -> IndexableExpr {
1943        let _locked = self.parent.lock().unwrap();
1944        let inner = unsafe { sys::xls_vast_parameter_ref_as_indexable_expression(self.inner) };
1945        IndexableExpr {
1946            inner,
1947            parent: self.parent.clone(),
1948        }
1949    }
1950}
1951
1952impl MacroRef {
1953    pub fn to_expr(&self) -> Expr {
1954        let _locked = self.parent.lock().unwrap();
1955        let inner = unsafe { sys::xls_vast_macro_ref_as_expression(self.inner) };
1956        Expr {
1957            inner,
1958            parent: self.parent.clone(),
1959        }
1960    }
1961}