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}