rust_hdl_core/
ast.rs

1use crate::bits::Bits;
2use crate::signed::Signed;
3use num_bigint::{BigInt, Sign};
4use std::fmt::{Display, Formatter, LowerHex};
5
6/// The BlackBox struct provides a way to wrap a blackbox,
7/// externally provided IP core.
8///
9/// You will frequently in the world of FPGA firmware need to
10/// wrap an external IP core that provides some functionality
11/// you cannot implement yourself.  For example, an analog
12/// clock driver circuit that takes a double ended clock and
13/// converts it to a single ended clock.  Your synthesis tools
14/// may be smart enough to infer such a device, but most likely
15/// they will need help.  That is where a black box references
16/// come in.  Think of it as a link reference
17/// to an external library.  Assuming you are going to validate
18/// the code using `yosys`, you will need to satisfy a few additional
19/// constraints.
20///
21/// 1.  You must provide a black box declaration for any module that
22/// is external to your RustHDL firmware, or `yosys` will fail to validate
23/// the resulting firmware.
24/// 2.  You must annotate that black box declaration in such a way that
25/// `yosys` knows the module is externally defined.
26/// 3.  RustHDL does not currently have the ability to dynamically rename
27/// conflicting instances of black box firmware.  So you can only include
28/// one instance of each black box firmware in your design.  This is generally
29/// _not_ what you want, and the [Wrapper] struct provides a better way
30/// to wrap a black box core (with some slight tradeoffs).
31///
32/// To use the [BlackBox] variant, you will need to provide a custom
33/// implementation of the [hdl] function in the [Logic] trait.  This
34/// is fairly straightforward to do, so lets look at some examples.
35///
36/// Example
37/// Let's imagine we have a module that represents a custom
38/// piece of hardware that takes a differential clock from
39/// outside the FPGA, and converts into a single ended clock
40/// to drive logic.  This is clearly going to be custom analog
41/// circuitry, so it's natural that we need to wrap an external
42/// black box primitive to get that functionality.
43///
44/// The [BlackBox] variant does not allow much flexibility.  Our
45/// RustHDL struct that describes the external IP must match
46/// the underlying Verilog exactly, or the included IP will not
47/// work correctly.  For the clock buffer, we have a Verilog
48/// definition from the manufacturer that looks like this
49/// ```verilog
50/// module IBUFDS(I, B, O);
51///    input I;
52///    input B;
53///    output O;
54/// endmodule
55/// ```
56///
57/// It's succinct, but the argument names are pretty terse.
58/// Unfortunately, we can't remap them or make it more ergonomic
59/// with a [BlackBox].  For those types of operations, we need
60/// to use a [Wrapper].  For now, we start with a struct to
61/// describe the circuit.  Note that at least the name of the
62/// RustHDL struct does not have to be the same as the black box
63/// IP core.
64///
65/// ```rust
66/// # use rust_hdl_core::prelude::*;
67/// pub struct ClockDriver {
68///    pub I: Signal<In, Clock>,
69///    pub B: Signal<In, Clock>,
70///    pub O: Signal<Out, Clock>,
71/// }
72/// ```
73/// We will use the [LogicBlock] derive macro to add the [Logic]
74/// trait to our circuit (so RustHDL can work with it), and the
75/// [Default] trait as well, to make it easy to use.
76/// The [Logic] trait for this circuit will need to be implemented
77/// by hand.
78/// ```rust
79/// # use rust_hdl_core:: prelude::*;
80/// # #[derive(LogicBlock, Default)]
81/// # pub struct ClockDriver {
82/// #   pub I: Signal<In, Clock>,
83/// #   pub B: Signal<In, Clock>,
84/// #   pub O: Signal<Out, Clock>,
85/// # }
86///
87/// impl Logic for ClockDriver {
88///     fn update(&mut self) {
89///         todo!()
90///     }
91///
92///     fn connect(&mut self) {
93///         todo!()
94///     }
95///
96///     fn hdl(&self) -> Verilog {
97///         todo!()
98///     }
99/// }
100/// ```
101///
102/// The [Logic] trait requires 3 methods [Logic::update], [Logic::connect],
103/// and [Logic::hdl].  The [Logic::update] method is used for simulation, and
104/// at the moment, black box modules are not simulatable.  So we can accept
105/// the default implementation of this.  The [Logic::connect] method is used
106/// to indicate which members of the circuit are _driven_ by the circuit.
107/// A better name might have been `drive`, instead of `connect`, but we will
108/// stick with the current terminology.  You can think of it in terms of an
109/// integrated circuit - outputs, are generally driven and are internally
110/// *connected*, while inputs are generally driven from outside and are externally
111/// connected.  For our black box, the [Logic::connect] trait implementation
112/// is very simple:
113/// ```rust
114/// # use rust_hdl_core:: prelude::*;
115/// # #[derive(LogicBlock, Default)]
116/// # pub struct ClockDriver {
117/// #   pub I: Signal<In, Clock>,
118/// #   pub B: Signal<In, Clock>,
119/// #   pub O: Signal<Out, Clock>,
120/// # }
121///
122/// impl Logic for ClockDriver {
123///     fn update(&mut self) {
124///         // No simulation model
125///     }
126///
127///     fn connect(&mut self) {
128///         self.O.connect();
129///     }
130///
131///     fn hdl(&self) -> Verilog {
132///         todo!()
133///     }
134/// }
135/// ```
136///
137/// Now, we need an implementation for the HDL for this Clock driver.
138/// That is where we need the [BlackBox] struct.
139///
140/// ```rust
141/// # use rust_hdl_core::prelude::*;
142/// # #[derive(LogicBlock, Default)]
143/// # pub struct ClockDriver {
144/// #   pub I: Signal<In, Clock>,
145/// #   pub B: Signal<In, Clock>,
146/// #   pub O: Signal<Out, Clock>,
147/// # }
148///
149/// impl Logic for ClockDriver {
150///     fn update(&mut self) {
151///     }
152///
153///     fn connect(&mut self) {
154///         self.O.connect();
155///     }
156///
157///      fn hdl(&self) -> Verilog {
158///         Verilog::Blackbox(BlackBox {
159///           code: r#"
160/// (* blackbox *)
161/// module IBUFDS(I, B, O)
162///   input I;
163///   input B;
164///   output O;
165/// endmodule"#.into(),
166///           name: "IBUFDS".into()
167///         })
168///      }
169/// }
170/// ```
171///
172/// Just to re-emphasize the point.  Your FPGA provider will give you a
173/// Verilog declaration for the IP core.  You cannot change it!  The names
174/// of the signals must be the same, even if Rust complains about your
175/// intransigence.
176///
177/// With all 3 of the methods implemented, we can now create an instance
178/// of our clock driver, synthesize it, and test it.  Here is the completed
179/// example:
180///
181/// ```rust
182/// # use rust_hdl_core::prelude::*;
183///
184/// #[derive(LogicBlock, Default)]
185/// pub struct ClockDriver {
186///   pub I: Signal<In, Clock>,
187///   pub B: Signal<In, Clock>,
188///   pub O: Signal<Out, Clock>,
189/// }
190///
191/// impl Logic for ClockDriver {
192///     fn update(&mut self) {
193///     }
194///
195///     fn connect(&mut self) {
196///         self.O.connect();
197///     }
198///
199///      fn hdl(&self) -> Verilog {
200///         Verilog::Blackbox(BlackBox {
201///           code: r#"
202/// (* blackbox *)
203/// module IBUFDS(I, B, O);
204///   input I;
205///   input B;
206///   output O;
207/// endmodule
208/// "#.into(),
209///           name: "IBUFDS".into()
210///         })
211///      }
212/// }
213///
214/// // For technical reasons, the top circuit of a RustHDL firmware
215/// // cannot be a black box.  So we use TopWrap to wrap it with one.
216/// let mut x = TopWrap::new(ClockDriver::default());
217/// x.uut.I.connect(); // Drive the positive clock from outside
218/// x.uut.B.connect(); // Drive the negative clock from outside
219/// x.connect_all();     // Wire up x and its internal components
220/// let v = generate_verilog(&x);  // Generates verilog and validates it
221/// yosys_validate("clock_driver", &v)?;
222/// # Ok::<(), SynthError>(())
223/// ```
224///
225/// Wrapping Parameteric IP Cores
226///
227/// The [BlackBox] variant has a couple of peculiarities that we have hidden in this
228/// example.  First, note that we pass the module name back to RustHDL in the
229/// [BlackBox] instantiation.  This is because RustHDL needs to know what the module
230/// is called so it can refer to it in the generated code.
231///
232/// In general RustHDL tries to avoid contention between modules with the same
233/// name by automatically namespacing them.  That means that if you have a
234/// module that is used in two different places in your code, it will get
235/// two different names.  This is because of the parametric nature of the
236/// generated code.  RustHDL does not assume (or know) that your two modules
237/// will generate identical Verilog.  So it assumes they will be different
238/// and creates two different named instances.
239///
240/// To see how that works, let's create a minimum example.  For test, we will
241/// use a single bit inverter.
242/// ```rust
243/// # use rust_hdl_core::prelude::*;
244///
245/// // First a basic inverter example
246/// #[derive(LogicBlock, Default)]
247/// struct Inverter {
248///    sig_in: Signal<In, Bit>,
249///    sig_out: Signal<Out, Bit>,
250/// }
251///
252/// // All it does is set the output signal to the inverse
253/// // of the input signal.
254/// impl Logic for Inverter {
255///    #[hdl_gen]
256///    fn update(&mut self) {
257///        self.sig_out.next = !self.sig_in.val();
258///    }
259/// }
260///
261/// // Now we create a circuit with 2 inverters connected
262/// // back to back.  The net result is a do-nothing (buffer?).
263/// #[derive(LogicBlock, Default)]
264/// struct DoubleKnot {
265///    sig_in: Signal<In, Bit>,
266///    sig_out: Signal<Out, Bit>,
267///    knot_1: Inverter,
268///    knot_2: Inverter,
269/// }
270///
271/// impl Logic for DoubleKnot {
272///    #[hdl_gen]
273///    fn update(&mut self) {
274///       self.knot_1.sig_in.next = self.sig_in.val();
275///       self.knot_2.sig_in.next = self.knot_1.sig_out.val();
276///       self.sig_out.next = self.knot_2.sig_out.val();
277///    }
278/// }
279///
280/// // Now, let's create a [DoubleKnot] and see what we get
281/// let mut x = DoubleKnot::default();
282/// // The `sig_in` input on `x` needs to be driven or connected
283/// x.sig_in.connect();
284/// x.connect_all();
285/// let v = generate_verilog(&x);
286/// // If you examine the generated code, you will see it contains
287/// // two instances of modules, one named `top$knot_1` and the
288/// assert!(v.contains("top$knot_1 knot_1"));
289/// // and the second is `top$knot_2`.
290/// assert!(v.contains("top$knot_2 knot_2"));
291/// ```
292/// The problem arises when you use a [BlackBox] Verilog declaration.
293/// In particular, RustHDL does not wrap your declaration (the Verilog is
294/// just copied to the output), so it does not know that two different
295/// instances of the same blackbox IP may represent different things.
296/// A classic case is in the case of a parameterized blackbox IP core.
297/// In that case, it is up to you to rename the different IP cores so that
298/// they do not conflict.  A better way around this is to use the [Wrapper]
299/// variant, since that is easier to use in most cases.
300#[derive(Debug, Clone)]
301pub struct BlackBox {
302    /// The Verilog code to create the black box in your firmware
303    pub code: String,
304    /// The name of the black box IP module.
305    pub name: String,
306}
307
308/// The [Wrapper] struct provides a more convenient and flexible way to wrap external
309/// IP cores than [BlackBox].
310///
311/// While you can wrap IP cores with [BlackBox], it has some limitations.
312/// There are two significant limits to using [BlackBox] to wrap IP cores,
313/// and [Wrapper] tries to fix them both.
314///
315/// - If your IP cores are parametric (for example, they take a
316/// parameter to determine an address or bitwidth), you must give them
317/// unique names to avoid problems with your toolchain.
318/// - You cannot rename or otherwise change any of the signal names
319/// going into the IP core when you use [BlackBox].
320///
321/// Using [Wrapper] addresses both problems.  To address the first
322/// problem, RustHDL (when using [Wrapper]), creates a wrapper module
323/// that hides the wrapped core from the global scope.  This additional
324/// level of scoping allows you to parameterize/customize the external
325/// IP core, without causing conflicts at the global scope.  The
326/// second problem is addressed also, since the [Wrapper] struct allows
327/// you to write Verilog "glue code" to either simplify or otherwise
328/// fix up the interface between the IP core and the RustHDL firmware
329/// around it.
330///
331/// To use the [Wrapper] you must provide a custom implementation of the [hdl]
332/// function in the [Logic] trait.  The [Wrapper] variant has two members.
333/// The first member is the [code] where you can write the Verilog glue
334/// code to instantiate the IP core, parameterize it, and connect it to the
335/// inputs and outputs of the RustHDL object.  The second member is the [cores]
336/// member, where you provide whatever blackbox code is required for the
337/// toolchain to accept your verilog.  This typically varies by toolchain.
338/// To get `yosys` to accept the verilog, you will need to provide `(* blackbox *)`
339/// attributes and module definitions for each external IP core.
340///
341/// Let's look at some examples.
342///
343/// Examples
344///
345/// In the [BlackBox] case, we looked at wrapping a clock buffer into an IP
346/// core.  Let's redo the same exercise, but with slightly better ergonomics.
347/// Here is the definition of the IP core provided by the FPGA vendor
348/// ```verilog
349/// module IBUFDS(I, B, O);
350///    input I;
351///    input B;
352///    output O;
353/// endmodule
354/// ```
355/// This core is very simple, but we will try and improve the ergonomics
356/// of it, and add a simulation model.
357///
358/// ```rust
359/// # use rust_hdl_core::prelude::*;
360/// pub struct ClockDriver {
361///    pub clock_p: Signal<In, Clock>,
362///    pub clock_n: Signal<In, Clock>,
363///    pub sys_clock: Signal<Out, Clock>,
364/// }
365/// ```
366///
367/// This time, our ClockDriver can use reasonable signal names, because
368/// we will use the glue layer to connect it to the IP core.  That glue
369/// layer is very helpful for remapping signals, combining them or
370/// assigning constant values.
371///
372/// We will also add a simulation model this time, to demonstrate how
373/// to do that for an external core.
374///
375/// As in the case of [BlackBox], we will use
376/// the [LogicBlock] derive macro to add the [Logic]
377/// trait to our circuit (so RustHDL can work with it), and the
378/// [Default] trait as well, to make it easy to use.
379/// The [Logic] trait for this circuit will need to be implemented
380/// by hand.
381///
382/// ```rust
383/// # use rust_hdl_core::prelude::*;
384/// # #[derive(LogicBlock, Default)]
385/// # pub struct ClockDriver {
386/// #   pub clock_p: Signal<In, Clock>,
387/// #   pub clock_n: Signal<In, Clock>,
388/// #   pub sys_clock: Signal<Out, Clock>,
389/// # }
390///
391/// impl Logic for ClockDriver {
392///     fn update(&mut self) {
393///         todo!()
394///     }
395///
396///     fn connect(&mut self) {
397///         todo!()
398///     }
399///
400///     fn hdl(&self) -> Verilog {
401///         todo!()
402///     }
403/// }
404/// ```
405///
406/// The [Logic] trait requires 3 methods [Logic::update], [Logic::connect],
407/// and [Logic::hdl].  The [Logic::update] method is used for simulation, and
408/// at the moment, black box modules are not simulatable.  So we can accept
409/// the default implementation of this.  The [Logic::connect] method is used
410/// to indicate which members of the circuit are _driven_ by the circuit.
411/// A better name might have been `drive`, instead of `connect`, but we will
412/// stick with the current terminology.  You can think of it in terms of an
413/// integrated circuit - outputs, are generally driven and are internally
414/// *connected*, while inputs are generally driven from outside and are externally
415/// connected.
416///
417/// We also want to create a simulation model for our IP core.  This is how
418/// RustHDL will know how to include the behavior of the core when it is
419/// integrated into simulations.  You can skip this step, of course, but
420/// then your black box IP cores will be pretty useless for simulation
421/// purposes.
422///
423/// A double-to-single ended clock driver is a fairly complicated
424/// piece of analog circuitry.  It normally sends a clock edge when
425/// the positive and negative going clocks cross.  For well behaved
426/// differential clocks (which is likely the case in simulation),
427/// this amounts to just buffering the positive clock, and ignoring
428/// the negative clock.  We will need to build a simulation model that
429/// includes enough detail to make it useful, but obviously, the
430/// fidelity will be limited.  For this example, we will opt to simply
431/// ignore the negative going clock, and forwarding the positive going clock
432/// (not a good idea in practice, but for simulations it's fine).
433///
434/// ```rust
435/// # use rust_hdl_core:: prelude::*;
436/// # #[derive(LogicBlock, Default)]
437/// # pub struct ClockDriver {
438/// #   pub clock_p: Signal<In, Clock>,
439/// #   pub clock_n: Signal<In, Clock>,
440/// #   pub sys_clock: Signal<Out, Clock>,
441/// # }
442///
443/// impl Logic for ClockDriver {
444///     fn update(&mut self) {
445///         self.sys_clock.next = self.clock_p.val();
446///     }
447///
448///     fn connect(&mut self) {
449///         self.sys_clock.connect();
450///     }
451///
452///     fn hdl(&self) -> Verilog {
453///         todo!()
454///     }
455/// }
456/// ```
457///
458/// Now, we need an implementation for the HDL for this Clock driver.
459/// That is where we need the [Wrapper] struct.
460///
461/// ```rust
462/// # use rust_hdl_core::prelude::*;
463/// # #[derive(LogicBlock, Default)]
464/// # pub struct ClockDriver {
465/// #   pub clock_p: Signal<In, Clock>,
466/// #   pub clock_n: Signal<In, Clock>,
467/// #   pub sys_clock: Signal<Out, Clock>,
468/// # }
469///
470/// impl Logic for ClockDriver {
471///     fn update(&mut self) {
472///         self.sys_clock.next = self.clock_p.val();
473///     }
474///
475///     fn connect(&mut self) {
476///         self.sys_clock.connect();
477///     }
478///
479///      fn hdl(&self) -> Verilog {
480///         Verilog::Wrapper(Wrapper {
481///           code: r#"
482///     // We can remap the names here
483///     IBUFDS ibufds_inst(.I(clock_p), .B(clock_n), .O(sys_clock));
484///
485/// "#.into(),
486///           cores: r#"
487/// (* blackbox *)
488/// module IBUFDS(I, B, O)
489///   input I;
490///   input B;
491///   output O;
492/// endmodule"#.into(),
493///         })
494///      }
495/// }
496/// ```
497///
498/// With all 3 of the methods implemented, we can now create an instance
499/// of our clock driver, synthesize it, and test it.  Here is the completed
500/// example:
501///
502/// ```rust
503/// # use rust_hdl_core::prelude::*;
504///
505/// #[derive(LogicBlock, Default)]
506/// pub struct ClockDriver {
507///   pub clock_p: Signal<In, Clock>,
508///   pub clock_n: Signal<In, Clock>,
509///   pub sys_clock: Signal<Out, Clock>,
510/// }
511///
512/// impl Logic for ClockDriver {
513///     fn update(&mut self) {
514///         self.sys_clock.next = self.clock_p.val();
515///     }
516///
517///     fn connect(&mut self) {
518///         self.sys_clock.connect();
519///     }
520///
521///      fn hdl(&self) -> Verilog {
522///         Verilog::Wrapper(Wrapper {
523///           code: r#"
524///     // This is basically arbitrary Verilog code that lives inside
525///     // a scoped module generated by RustHDL.  Whatever IP cores you
526///     // use here must have accompanying core declarations in the
527///     // cores string, or they will fail verification.
528///     //
529///     // In this simple case, we remap the names here
530///     IBUFDS ibufds_inst(.I(clock_p), .B(clock_n), .O(sys_clock));
531///
532/// "#.into(),
533///           cores: r#"
534/// (* blackbox *)
535/// module IBUFDS(I, B, O);
536///   input I;
537///   input B;
538///   output O;
539/// endmodule"#.into(),
540///         })
541///      }
542/// }
543///
544/// // Let's create our ClockDriver.  No [TopWrap] is required here.
545/// let mut x = ClockDriver::default();
546/// x.clock_p.connect(); // Drive the positive clock from outside
547/// x.clock_n.connect(); // Drive the negative clock from outside
548/// x.connect_all();     // Wire up x and its internal components
549/// let v = generate_verilog(&x);  // Generates verilog and validates it
550/// yosys_validate("clock", &v)?;
551/// # Ok::<(), SynthError>(())
552/// ```
553///
554#[derive(Debug, Clone)]
555pub struct Wrapper {
556    /// The Verilog code to instantiate the black box core, and connect
557    /// its inputs to the argument of the current LogicBlock kernel.
558    pub code: String,
559    /// Blackbox core declarations needed by some synthesis tools (like yosys)
560    pub cores: String,
561}
562
563/// The [Verilog] type is used to represent the Verilog translation of a
564/// RustHDL kernel.  You will only need it if implementing blackbox cores
565/// or wrapping external Verilog code.
566#[derive(Debug, Clone)]
567pub enum Verilog {
568    /// Use [Empty] when you do not want a module represented in Verilog at all
569    Empty,
570    #[doc(hidden)]
571    Combinatorial(VerilogBlock),
572    /// Custom Verilog for a RustHDL module
573    Custom(String),
574    /// Blackbox for referencing IP cores.
575    Blackbox(BlackBox),
576    /// Wrap an external IP core or Verilog code into a RustHDL module.
577    Wrapper(Wrapper),
578}
579
580impl Default for Verilog {
581    fn default() -> Self {
582        Self::Empty
583    }
584}
585
586#[doc(hidden)]
587pub type VerilogBlock = Vec<VerilogStatement>;
588
589#[doc(hidden)]
590#[derive(Debug, Clone)]
591pub enum VerilogStatement {
592    Assignment(VerilogExpression, VerilogExpression),
593    SliceAssignment {
594        base: VerilogExpression,
595        width: usize,
596        offset: VerilogExpression,
597        replacement: VerilogExpression,
598    },
599    If(VerilogConditional),
600    Match(VerilogMatch),
601    Loop(VerilogLoop),
602    Comment(String),
603    Link(Vec<VerilogLink>),
604    Macro(VerilogBlock),
605}
606
607#[doc(hidden)]
608#[derive(Debug, Clone)]
609pub enum VerilogLink {
610    Forward(VerilogLinkDetails),
611    Backward(VerilogLinkDetails),
612    Bidirectional(VerilogLinkDetails),
613}
614
615#[doc(hidden)]
616#[derive(Debug, Clone)]
617pub struct VerilogLinkDetails {
618    pub my_name: String,
619    pub owner_name: String,
620    pub other_name: String,
621}
622
623#[doc(hidden)]
624#[derive(Debug, Clone)]
625pub struct VerilogIndexAssignment {
626    pub target: VerilogExpression,
627    pub index: VerilogExpression,
628    pub value: VerilogExpression,
629}
630
631#[doc(hidden)]
632#[derive(Debug, Clone)]
633pub struct VerilogConditional {
634    pub test: VerilogExpression,
635    pub then: VerilogBlock,
636    pub otherwise: VerilogBlockOrConditional,
637}
638
639#[doc(hidden)]
640#[derive(Debug, Clone)]
641pub struct VerilogLoop {
642    pub index: String,
643    pub from: VerilogLiteral,
644    pub to: VerilogLiteral,
645    pub block: VerilogBlock,
646}
647
648#[doc(hidden)]
649#[derive(Debug, Clone)]
650pub enum VerilogBlockOrConditional {
651    Block(VerilogBlock),
652    Conditional(Box<VerilogStatement>),
653    None,
654}
655
656#[doc(hidden)]
657#[derive(Debug, Clone)]
658pub struct VerilogMatch {
659    pub test: VerilogExpression,
660    pub cases: Vec<VerilogCase>,
661}
662
663#[doc(hidden)]
664#[derive(Debug, Clone)]
665pub struct VerilogCase {
666    pub condition: String,
667    pub block: VerilogBlock,
668}
669
670#[doc(hidden)]
671#[derive(Debug, Clone)]
672pub struct VerilogLiteral {
673    val: BigInt,
674    bits: usize,
675}
676
677impl VerilogLiteral {
678    pub fn as_usize(&self) -> usize {
679        let m = self.val.to_u32_digits();
680        assert!(m.0 != Sign::Minus);
681        let m = m.1;
682        match m.len() {
683            0 => 0,
684            1 => m[0] as usize,
685            _ => panic!("Loop index is too large!"),
686        }
687    }
688}
689
690impl From<bool> for VerilogLiteral {
691    fn from(x: bool) -> Self {
692        let bi: BigInt = u32::from(x).into();
693        VerilogLiteral { val: bi, bits: 1 }
694    }
695}
696
697macro_rules! define_literal_from_uint {
698    ($name: ident, $width: expr) => {
699        impl From<$name> for VerilogLiteral {
700            fn from(x: $name) -> Self {
701                let bi: BigInt = x.into();
702                VerilogLiteral {
703                    val: bi,
704                    bits: $width,
705                }
706            }
707        }
708    };
709}
710
711define_literal_from_uint!(u128, 128);
712define_literal_from_uint!(u64, 64);
713define_literal_from_uint!(i32, 32);
714define_literal_from_uint!(u32, 32);
715define_literal_from_uint!(u16, 16);
716define_literal_from_uint!(u8, 8);
717#[cfg(target_pointer_width = "64")]
718define_literal_from_uint!(usize, 64);
719#[cfg(target_pointer_width = "32")]
720define_literal_from_uint!(usize, 32);
721
722impl<const N: usize> From<Bits<N>> for VerilogLiteral {
723    fn from(x: Bits<N>) -> Self {
724        let mut z = BigInt::default();
725        for i in 0..N {
726            z.set_bit(i as u64, x.get_bit(i));
727        }
728        VerilogLiteral { val: z, bits: N }
729    }
730}
731
732impl<const N: usize> From<Signed<N>> for VerilogLiteral {
733    fn from(x: Signed<N>) -> Self {
734        VerilogLiteral {
735            val: x.bigint(),
736            bits: N,
737        }
738    }
739}
740
741impl Display for VerilogLiteral {
742    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
743        let bits = self.bits;
744        Display::fmt(&bits, f)?;
745        Display::fmt("'", f)?;
746        if bits % 4 != 0 && self.bits < 20 {
747            Display::fmt("b", f)?;
748            std::fmt::Binary::fmt(&self.val, f)
749        } else {
750            Display::fmt("h", f)?;
751            std::fmt::LowerHex::fmt(&self.val, f)
752        }
753    }
754}
755
756impl LowerHex for VerilogLiteral {
757    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
758        let bits = self.bits;
759        Display::fmt(&bits, f)?;
760        Display::fmt("'h", f)?;
761        LowerHex::fmt(&self.val, f)
762    }
763}
764
765#[doc(hidden)]
766#[derive(Debug, Clone)]
767pub enum VerilogExpression {
768    Signal(String),
769    Literal(VerilogLiteral),
770    Cast(Box<VerilogExpression>, usize),
771    Signed(Box<VerilogExpression>),
772    Unsigned(Box<VerilogExpression>),
773    Paren(Box<VerilogExpression>),
774    Binary(Box<VerilogExpression>, VerilogOp, Box<VerilogExpression>),
775    Unary(VerilogOpUnary, Box<VerilogExpression>),
776    Index(Box<VerilogExpression>, Box<VerilogExpression>),
777    Slice(Box<VerilogExpression>, usize, Box<VerilogExpression>),
778    IndexReplace(
779        Box<VerilogExpression>,
780        Box<VerilogExpression>,
781        Box<VerilogExpression>,
782    ),
783}
784
785#[doc(hidden)]
786#[derive(Debug, Clone)]
787pub enum VerilogOp {
788    Add,
789    Sub,
790    Mul,
791    LogicalAnd,
792    LogicalOr,
793    BitXor,
794    BitAnd,
795    BitOr,
796    Shl,
797    Shr,
798    Eq,
799    Lt,
800    Le,
801    Ne,
802    Ge,
803    Gt,
804}
805
806#[doc(hidden)]
807#[derive(Debug, Clone)]
808pub enum VerilogOpUnary {
809    Not,
810    Neg,
811    All,
812    Any,
813    Xor,
814}