rust_hdl/
lib.rs

1//! ** Write FPGA Firmware using Rust! **
2//!
3//!
4//! RustHDL is a crate that allows you to write FPGA firmware using Rust!
5//! Specifically, `rust-hdl` compiles a subset of Rust down to Verilog so that
6//! you can synthesize firmware for your FPGA using standard tools.  It also
7//! provides tools for simulation, verification, and analysis along with strongly
8//! typed interfaces for making sure your design works before heading to the bench.
9//! The workflow is very similar to GPU programming.  You write everything in Rust,
10//! including an update `kernel` that compiles down onto the hardware.  You can simulate
11//! and verify everything from the safety and comfort of your Rust environment, and
12//! then head over to standard synthesis tools to get files that program your FPGA.
13//!
14//! ## Links
15//!
16//! You may want:
17//!
18//! - [API Documentation](https://docs.rs/rust-hdl/latest/rust_hdl/)
19//! - [GitHub](https://github.com/samitbasu/rust-hdl)
20//! - [Home Page](https://rust-hdl.org)
21//!
22//! ## Features
23//! * Safe - have Rust check the validity of your firmware with
24//! strongly typed interfaces at **compile** time, as well as at
25//! run time, synthesis, and on the device.
26//! * Fast - Run simulations of your designs straight from your
27//! Rust code, with pretty good simulation performance.
28//! * Readable - RustHDL outputs Verilog code for synthesis and
29//! implementation, and goes through some effort to make sure that
30//! code is readable and understandable, in case you need to resolve
31//! timing issues or other conflicts.
32//! * Reusable - RustHDL supports templated firmware for parametric
33//! use, as well as a simple composition model based on structs.
34//! * Batteries Included - RustHDL includes a set of basic firmware
35//! widgets that provide FIFOs, RAMs and ROMs, Flip flops, SPI components,
36//! PWMs etc, so you can get started quickly.
37//! * Free - Although you can use RustHDL to wrap existing IP cores,
38//! all of the RustHDL code and firmware is open source and free to use (as in speech and beer).
39//! * Tested - RustHDL has been used to write firmware that is shipping in commercial products.
40//! This includes quite complicated designs that use nearly all of a moderately sized FPGA,
41//! and take advantage of specialized hardware in the FPGAs themselves.
42//!
43//! ## Quickstart
44//!
45//! The definitive example in FPGA firmware land is a simple LED blinker.  This typically
46//! involves a clock that is fed to the FPGA with a pre-defined frequency, and an output
47//! signal that can control an LED.  Because we don't know what FPGA we are using, we will
48//! do this in simulation first.  We want a blink that is 250 msec long every second, and
49//! our clock speed is (a comically slow) 10kHz.  Here is a minimal working Blinky! example:
50//!
51//! ```
52//! use std::time::Duration;
53//! use rust_hdl::prelude::*;
54//!
55//! const CLOCK_SPEED_HZ : u64 = 10_000;
56//!
57//! #[derive(LogicBlock)]  // <- This turns the struct into something you can simulate/synthesize
58//! struct Blinky {
59//!     pub clock: Signal<In, Clock>, // <- input signal, type is clock
60//!     pulser: Pulser,               // <- sub-circuit, a widget that generates pulses
61//!     pub led: Signal<Out, Bit>,    // <- output signal, type is single bit
62//! }
63//!
64//! impl Default for Blinky {
65//!    fn default() -> Self {
66//!        Self {
67//!          clock: Default::default(),
68//!          pulser: Pulser::new(CLOCK_SPEED_HZ, 1.0, Duration::from_millis(250)),
69//!          led: Default::default(),
70//!        }
71//!     }
72//! }
73//!
74//! impl Logic for Blinky {
75//!     #[hdl_gen] // <- this turns the update function into an HDL Kernel that can be turned into Verilog
76//!     fn update(&mut self) {
77//!        // v-- write to the .next member     v-- read from .val() method
78//!        self.pulser.clock.next = self.clock.val();
79//!        self.pulser.enable.next = true.into();
80//!        self.led.next = self.pulser.pulse.val();
81//!     }
82//! }
83//!
84//! fn main() {
85//!     // v--- build a simple simulation (1 testbench, single clock)
86//!     let mut sim = simple_sim!(Blinky, clock, CLOCK_SPEED_HZ, ep, {
87//!         let mut x = ep.init()?;
88//!         wait_clock_cycles!(ep, clock, x, 4*CLOCK_SPEED_HZ);
89//!         ep.done(x)
90//!     });
91//!
92//!     // v--- construct the circuit
93//!     let mut uut = Blinky::default();
94//!     // v--- run the simulation, with the output traced to a .vcd file
95//!     sim.run_to_file(Box::new(uut), 5 * SIMULATION_TIME_ONE_SECOND, "blinky.vcd").unwrap();
96//!     vcd_to_svg("/tmp/blinky.vcd","images/blinky_all.svg",&["uut.clock", "uut.led"], 0, 4_000_000_000_000).unwrap();
97//!     vcd_to_svg("/tmp/blinky.vcd","images/blinky_pulse.svg",&["uut.clock", "uut.led"], 900_000_000_000, 1_500_000_000_000).unwrap();
98//! }
99//! ```
100//!
101//! Running the above (a release run is highly recommended) will generate a `vcd` file (which is
102//! a trace file for FPGAs and hardware in general).  You can open this using e.g., `gtkwave`.
103//! If you have, for example, an Alchitry Cu board you can generate a bitstream for this exampling
104//! with a single call.  It's a little more involved, so we will cover that in the detailed
105//! documentation.  It will also render that `vcd` file into an `svg` you can view with an ordinary
106//! web browser.  This is the end result showing the entire simulation:
107//! ![blinky_all](https://github.com/samitbasu/rust-hdl/raw/main/rust-hdl/images/blinky_all.svg)
108//! Here is a zoom in showing the pulse to the LED
109//! ![blinky_pulse](https://github.com/samitbasu/rust-hdl/raw/main/rust-hdl/images/blinky_pulse.svg)
110//!
111//! The flow behind RustHDL is the following:
112//!
113//! - Circuits are modelled using simple `struct`s, composed of other circuit elements and
114//! signal wires that interconnect them.
115//! - A `#[derive(LogicBlock)]` annotation on the struct adds autogenerated code needed by
116//! RustHDL.
117//! - You `impl Logic` on your `struct`, and provide the `fn update(&mut self)` method, which
118//! is the HDL update kernel.
119//! - That gets annotated with a `#[hdl_gen]` attribute to generate HDL from the Rust code
120//! - You can then simulate and synthesize your design - either in software, or by using an
121//! appropriate BSP and toolchain.
122//!
123//! The rest is detail.  Some final things to keep in mind.
124//!
125//! - RustHDL is a strict subset of Rust.  The `rustc` compiler must be satisfied with your
126//! design first.  That means types, exhaustive enum matching, etc.
127//! - The goal is to eliminate a class of mistakes that are easy to make in other HDLs with
128//! checks taking place at compile time, via static analysis at run time, and then with
129//! testbenches.
130//! - Although the performance can always be improved, RustHDL is pretty fast, especially in
131//! release mode.
132//!
133//! ## Types
134//!
135//! There are a couple of key types you should be comfortable with to use RustHDL.  The first
136//! is the [Bits](core::bits::Bits) type, which provides a compile-time arbitrary width bit vector.
137//!
138//! ### Representing bits
139//!
140//! The [Bits](core::bits::Bits) type is a `Copy` enabled type that you can construct from integers,
141//! from the `Default` trait, or from other `Bits`.    Mostly, it is meant to stay out of your way
142//! and behave like a `u32`.
143//!
144//! ```
145//! # use rust_hdl::prelude::*;
146//! let x: Bits<50> = Default::default();
147//! ```
148//! This will construct a length 50 bit vector that is initialized to all `0`.
149//!
150//! You can also convert from literals into bit vectors using the [From] and [Into] traits,
151//! provided the literals are of the `u64` type.
152//!
153//! ```
154//! # use rust_hdl::prelude::*;
155//! let x: Bits<50> = 0xBEEF.into();
156//! ```
157//!
158//! In some cases, Rust complains about literals, and you may need to provide a suffix:
159//! ```
160//! # use rust_hdl::prelude::*;
161//! let x: Bits<50> = 0xDEAD_BEEF_u64.into();
162//! ```
163//! However, in most cases, you can leave literals suffix-free, and Rust will automatically
164//! determine the type from the context.
165//!
166//! You can construct a larger constant using the [bits] function.  If you have a literal of up to
167//! 128 bits, it provides a functional form
168//! ```
169//! # use rust_hdl::prelude::*;
170//! let x: Bits<200> = bits(0xDEAD_BEEE); // Works for up to 128 bit constants.
171//! ```
172//!
173//! There is also the [ToBits] trait, which is implemented on the basic unsigned integer types.
174//! This trait allows you to handily convert from different integer values
175//!
176//! ```
177//! # use rust_hdl::prelude::*;
178//! let x: Bits<10> = 32_u8.to_bits();
179//! ```
180//!
181//! ### Operations
182//!
183//! The [Bits](core::bits::Bits) type supports a subset of operations that can be synthesized in
184//! hardware.  You can perform
185//!
186//! * Addition between `Bits` of the same size using the `+` operator
187//! * Subtraction between `Bits` of the same size using the `-` operator
188//! * Bitwise logical `AND` between `Bits` of the same size using the `&` operator
189//! * Bitwise logical `OR` between `Bits` of the same size using the `|` operator
190//! * Bitwise logical `XOR` (Exclusive Or) between `Bits` of the same size using the `^` operator
191//! * Bitwise comparisons for equality between `Bits` of the same size using `==` and `!=` operators
192//! * Unsigned comparisons (e.g., `>,>=,<,<=`) between `Bits` of the same size - these are
193//! always treated as unsigned values for comparison purposes.
194//! * Shift left using the `<<` operator
195//! * Shift right (no sign extension!) using the '>>' operator
196//! * Bitwise logical `NOT` using the `!` prefix operator
197//!
198//! These should feel natural when using RustHDL, as expressions follow Rust's rules (and not Verilog's).
199//! For example:
200//! ```rust
201//! # use rust_hdl::prelude::*;
202//! let x: Bits<32> = 0xDEAD_0000_u32.to_bits();
203//! let y: Bits<32> = 0x0000_BEEF_u32.to_bits();
204//! let z = x + y;
205//! assert_eq!(z, 0xDEAD_BEEF_u32.to_bits());
206//! ```
207//!
208//! You can, of course, construct expressions of arbitrary complexity using parenthesis, etc.
209//! The only real surprise may be at synthesis time, when you try to fit the expression onto hardware.
210//!
211//! ### Signal Type
212//!
213//! *Signals are software abstractions to represent physical wires*.  The [Signal](core::signal::Signal)
214//!type is generic over a couple of parameters.  The first is meant to indicate the driver of the wire.
215//! In RustHDL, every wire must have exactly one driver.  It is the hardware equivalent of the
216//! single writer principle.  You can have as many readers as you want, but only one writer.  Unfortunately,
217//! there are some subtleties here, and declaring ownership of a wire using the type system is
218//! imperfect.  Instead, we settle for a signalling mechanism of _intent_.  So you mark a
219//! signal as how you intend to use it in your logic.  For example, consider the following circuit:
220//!
221//! ```rust
222//! # use rust_hdl::prelude::*;
223//!
224//! pub struct My8BitAdder {
225//!    pub input_1: Signal<In, Bits<8>>,
226//!    pub input_2: Signal<In, Bits<8>>,
227//!    pub output: Signal<Out, Bits<8>>,
228//! }
229//! ```
230//! In this case, the fields of the adder circuit are marked as `pub` so they can be accessed from
231//! outside the circuit.  The [Direction](core::signal::Direction) argument to the [Signal] indicates
232//! how the given circuit intends to utilize the various wires.  In this case, `input_1` and `input_2`
233//! should be considered inputs, and `output` is, obviously, an output.  As such, `My8BitAdder` is
234//! promising you that it will drive the `output` wire.  If it fails to actually do so (by leaving
235//! it undriven), then you will get an error when you try to use it in a design.
236//!
237//! *RustHDL does not allow undriven nets*.  They are treated similarly to uninitialized memory in Rust.
238//! You _must_ drive every net in the design.  Furthermore, you can have only one driver for each
239//! net.  These two principles are core to RustHDL!
240//!
241//! The second part of a [Signal] is that it is _typed_.  In general, the type signature is meant
242//! to convey something about the nature of the data being stored or passed.  In the case of
243//! `My8BitAdder`, it doesn't say much - only that the input is an unsigned 8-bit value.  But
244//! the types can be more complicated, including collections of signals running in multiple
245//! directions (as is typical for a bus or other complex interface).
246//!
247//! Signals can also be bidirectional with the [InOut](core::signal::Direction::InOut) designation.
248//! But you typically can only use these types of signals at the edge of your device.  More on that
249//! elsewhere.
250//!
251//! The definition of [Signal] also indicates how it should be used.  [Signal]'s cannot be
252//! assigned to using usual semantics.
253//! ```
254//! # use rust_hdl::prelude::*;
255//!
256//! #[derive(Clone, Debug)]
257//! pub struct Signal<D: Direction, T: Synth> {
258//!     pub next: T,
259//!     pub changed: bool,
260//!     // Internal details omitted
261//!#     dir: std::marker::PhantomData<D>,
262//! }
263//!```
264//!
265//! To change (drive) the value of a signal, you assign to the `next` field.  To read the
266//! value of the signal (i.e. to get it's current state without driving it), you use the `val()` method.
267//! This is in keeping with the idea that you treat the signal differently if you want to drive
268//! it to some value, versus if you want to read it, as in hardware, these are different functions.
269//! In most cases, you will read from `val()` of the input signals, and write to the `.next` of the
270//! output signal.  For example, in the `My8BitAdder` example, you would read from `input_1.val()`
271//! and from `input_2.val()`, and write to `output.next`.  Like this:
272//!
273//! ```
274//! # use rust_hdl::prelude::*;
275//!
276//! pub struct My8BitAdder {
277//!    pub input_1: Signal<In, Bits<8>>,
278//!    pub input_2: Signal<In, Bits<8>>,
279//!    pub output: Signal<Out, Bits<8>>,
280//! }
281//!
282//! impl Logic for My8BitAdder {
283//!    fn update(&mut self) {
284//!        self.output.next = self.input_1.val() + self.input_2.val();
285//!    }
286//! }
287//!
288//! ```
289//!
290//! In general, this is the pattern to follow.  However, there are some exceptions.  Sometimes,
291//! you will want a "scratchpad" for holding intermediate results in a longer expression.
292//! For example, suppose you want to logically OR a bunch of values together, but want to
293//! logically shift them into different positions before doing so.  Let us assume you have
294//! a logical block that looks like this:
295//!
296//! ```
297//! # use rust_hdl::prelude::*;
298//!
299//! pub struct OrStuff {
300//!    pub val1: Signal<In, Bit>,
301//!    pub val2: Signal<In, Bits<4>>,
302//!    pub val3: Signal<In, Bits<2>>,
303//!    pub val4: Signal<In, Bit>,
304//!    pub combined: Signal<Out, Bits<8>>,
305//!    pad: Signal<Local, Bits<8>>,
306//! }
307//! ```
308//!
309//! In this case, the `pad` field (which is private to the logic) has a direction of `Local`,
310//! which means it can be used to write and read from in the same circuit, as _long as you write first_!
311//! Hence, you can do something like this in the `update` method
312//!
313//! ```
314//! # use rust_hdl::prelude::*;
315//!
316//!# pub struct OrStuff {
317//!#    pub val1: Signal<In, Bit>,
318//!#    pub val2: Signal<In, Bits<4>>,
319//!#    pub val3: Signal<In, Bits<2>>,
320//!#    pub val4: Signal<In, Bit>,
321//!#    pub combined: Signal<Out, Bits<8>>,
322//!#    pad: Signal<Local, Bits<8>>,
323//!# }
324//!
325//! impl Logic for OrStuff {
326//!    fn update(&mut self) {
327//!       self.pad.next = 0.into(); // Write first
328//!       self.pad.next = self.pad.val() | bit_cast::<8,1>(self.val1.val().into()); // Now we can read and write to it
329//!       self.pad.next = self.pad.val() | (bit_cast::<8,4>(self.val2.val()) << 1);
330//!       self.pad.next = self.pad.val() | (bit_cast::<8,2>(self.val3.val()) << 5);
331//!       self.pad.next = self.pad.val() | (bit_cast::<8,1>(self.val4.val().into()) << 7);
332//!       self.combined.next = self.pad.val();
333//!    }
334//! }
335//! ```
336//!
337//! You can understand this behavior by either "folding" all of the expressions into a single
338//! long expression (i.e., by eliminating `self.pad` altogether) and just assigning the output
339//! to an expression consisting of the various inputs OR-ed together.  Nonetheless, it is
340//! handy to be able to compute intermediate values and read them back elsewhere in the code.
341//!
342//! * Note that `.next` should _never_ appear on the right hand side of an expression! *
343//!
344//! The following code will fail to compile, because once we try to derive HDL from the result,
345//! RustHDL realizes it makes no sense.
346//!
347//! ```compile_fail
348//! # use rust_hdl::prelude::*;
349//!# pub struct OrStuff {
350//!#    pub val1: Signal<In, Bit>,
351//!#    pub val2: Signal<In, Bits<4>>,
352//!#    pub val3: Signal<In, Bits<2>>,
353//!#    pub val4: Signal<In, Bit>,
354//!#    pub combined: Signal<Out, Bits<8>>,
355//!#    pad: Signal<Local, Bits<8>>,
356//!# }
357//! impl Logic for OrStuff {
358//!    #[hdl_gen]
359//!    fn update(&mut self) {
360//!       self.pad.next = 0.into(); // Write first
361//!       self.pad.next = self.pad.next | bit_cast::<8,1>(self.val1.val().into()); // Fails!  Can only write to .next
362//!       self.combined.next = self.pad.val();
363//!    }
364//! }
365//!```
366//!
367//! Detecting the case in which you fail to write to a signal before reading from it is more complicated
368//! and must be done a run time.  The macro processor is not sophisticated enough to detect that case at the moment.
369//! However, it can be found when your logic is checked for correctness by the static analyzer.
370//!
371//! Normally, the Verilog code generator or the Simulation engine will statically check your design for you.
372//! However, you can also check the design yourself using the [check_all](core::check_error::check_all)
373//! function.  Here is an example of that check being run on a logic block that attempts to write
374//! to an input signal being passed into the block.  The example panics because
375//!
376//!```should_panic
377//! # use rust_hdl::prelude::*;
378//!
379//! #[derive(LogicBlock, Default)]
380//! struct BadActor {
381//!   pub in1: Signal<In, Bit>,
382//!   pub in2: Signal<In, Bit>,
383//!   pub out1: Signal<Out, Bit>,
384//! }
385//!
386//! impl Logic for BadActor {
387//!   #[hdl_gen]
388//!   fn update(&mut self) {
389//!        // This is definitely not OK
390//!        self.in1.next = true;
391//!        // This is fine
392//!        self.out1.next = self.in2.val();
393//!    }
394//! }
395//!
396//! // This will panic with an error of CheckError::WritesToInputs, pointing to self.in1
397//! check_all(&BadActor::default()).unwrap()
398//! ```
399//!
400//! ## Traits
401//!
402//! There is only one trait that you typically need to implement to get things to work in RustHDL
403//! with the simulation and synthesis frameworks.  That is the [Logic](core::logic::Logic) trait.
404//! Although you will rarely (if ever) need to implement the methods themselves, here is the
405//! full definition of the trait:
406//!```
407//! # use rust_hdl::prelude::*;
408//!
409//! pub trait Logic {
410//!     fn update(&mut self);
411//!     fn connect(&mut self) {}
412//!     fn hdl(&self) -> Verilog {
413//!         Verilog::Empty
414//!     }
415//!     fn timing(&self) -> Vec<TimingInfo> {
416//!         vec![]
417//!     }
418//! }
419//! ```
420//!
421//! The methods are quite simple:
422//!
423//! * `update` - this updates the state of the logical block based on the inputs and internal state.
424//! In general, this is where the action of the logical block takes place.
425//! * `connect` - this is where we claim whatever signals we drive, by calling `connect` on them.
426//! * `hdl` - this method returns the Verilog description for our logical block in the form of
427//! an [Verilog](core::ast::Verilog) enum.
428//! * `timing` - this is where specific timing exceptions or requirements are expressed for the
429//! logical block.
430//!
431//! In almost all cases, you will use the `#[derive(LogicBlock)]` macro to derive all of the traits from
432//! your own `update` method, written in Rust.  If we revisit the `Blinky` example, note that
433//! we only provided the `update` method, with an attribute of `#[hdl_gen]`, which in turn
434//! generated the remaining trait implementations:
435//! ```
436//! # use std::time::Duration;
437//! # use rust_hdl::prelude::*;
438//! # use rust_hdl::docs::vcd2svg::vcd_to_svg;
439//!
440//! # const CLOCK_SPEED_HZ : u64 = 10_000;
441//!
442//! #[derive(LogicBlock)]
443//! struct Blinky {
444//!     pub clock: Signal<In, Clock>,
445//!     pulser: Pulser,
446//!     pub led: Signal<Out, Bit>,
447//! }
448//!
449//! # impl Default for Blinky {
450//! #   fn default() -> Self {
451//! #       Self {
452//! #         clock: Default::default(),
453//! #         pulser: Pulser::new(CLOCK_SPEED_HZ, 1.0, Duration::from_millis(250)),
454//! #         led: Default::default(),
455//! #       }
456//! #    }
457//! # }
458//!
459//! impl Logic for Blinky {
460//!     #[hdl_gen]
461//!     fn update(&mut self) {
462//!        self.pulser.clock.next = self.clock.val();
463//!        self.pulser.enable.next = true.into();
464//!        self.led.next = self.pulser.pulse.val();
465//!     }
466//! }  
467//!```
468//!
469//! There are a couple of other traits that RustHDL uses that you should be aware of.
470//!
471//! - `Synth` - this trait is provided on types that can be represented in hardware, i.e. as
472//! a set of bits.  You will probably not need to implement this trait yourself, but if you
473//! need some special type representation `Foo`, and `impl Synth for Foo`, then RustHDL will
474//! be able to generate Verilog code for it.
475//! - `Block` - this trait is needed on any `struct` that is a composition of circuit elements
476//! (pretty much every struct used to model a circuit).  This should be auto-derived.
477//! - `Logic` - Sometimes, you will need to override the default implementations of the `Logic`
478//!trait.  In those cases, (when you are providing a custom simulation model, or wrapping a
479//!black box Verilog routine), you will need to `impl` the other methods.
480//!
481//! ## The Synthesizable Subset of Rust and the HDL Kernel
482//!
483//! RustHDL uses procedural macros to define a subset of the Rust language that can be used to
484//! describe actual hardware.  That subset is known as the synthesizable subset of Rust.  It is
485//! quite limited because the end result is translated into Verilog and ultimately into hardware
486//! configuration for the FPGA.
487//!
488//! - The HDL kernel must be valid Rust!  If you remove the `#[hdl_gen]` attribute, the code
489//! must still be accepted by `rustc`!  That means you must satisfy the type constraints, the
490//! private nature of the struct fields, etc.  This is one of the major benefits of RustHDL.  It
491//! takes code that is already been checked by `rustc` and then converts it into HDL.
492//!
493//! So this will _clearly_ fail to compile.
494//!
495//! ```compile_fail
496//! # use rust_hdl::prelude::*;
497//!
498//! struct Foo {
499//!  bar: Signal<Out, Bits<4>>
500//! }
501//!
502//! impl Logic for Foo {
503//!    #[hdl_gen]
504//!    fn update(&mut self) {
505//!       self.bar.next = "Oy!"; // Type issue here...
506//!    }
507//! }
508//! ```
509//!
510//! - The `#[hdl_gen]` attribute can only be applied to a function (aka HDL Kernel) that
511//! takes `&mut self` as an argument. In almost all cases, you will write something like:
512//!
513//! ```
514//!# use rust_hdl::prelude::*;
515//!
516//! struct Foo {}
517//!
518//! impl Logic for Foo {
519//!   #[hdl_gen]
520//!   fn update(&mut self) {
521//!      // Put your synthesizable subset of Rust here...
522//!   }
523//! }
524//! ```
525//!
526//! - The body of the `update` function must be a single block, consisting of statements.
527//! Local definitions and items are not allowed in HDL kernels.  The following, for example, will
528//!fail.  This is an example of valid Rust that is not allowed in an HDL kernel.
529//!
530//!```compile_fail
531//! # use rust_hdl::prelude::*;
532//!
533//! struct Foo {}
534//!
535//! impl Logic for Foo {
536//!    #[hdl_gen]
537//!    fn update (&mut self) {
538//!      // Fails because local items are not allowed in HDL kernels.
539//!      let x = 32;
540//!    }
541//! }
542//!```
543//!
544//! - Assignments are allowed as long as you follow the rules about signals.  Types are
545//! still enforced by Rust.
546//!     - Indexed assignments are currently not supported
547//!     - Signal assignments must be to either `.next` or `.next.field` if the signal is struct based.
548//!
549//! So valid assignments will be of the form `self.<signal>.next = <expr>`, or for structure-valued
550//! signals.
551//!
552//! - Expressions support accessing fields of a signal
553//! - Binary operations supported are `+`, `-`, `*`, `&&`, `||`, `^`, `&`, `|`, `<<`, `>>`, `==`, `<`, `<=`, `!=`, `>`, `>=`
554//! In general, binary operations require that both arguments are of the same type (e.g. bitwidth) or one of the
555//! arguments will be a literal.
556//! ```rust
557//! # use rust_hdl::prelude::*;
558//!
559//! struct Foo {
560//!    pub sig1: Signal<In, Bits<4>>,
561//!    pub sig2: Signal<In, Bits<4>>,
562//!    pub sig3: Signal<Out, Bits<4>>,
563//! }
564//!
565//! impl Logic for Foo {
566//!    #[hdl_gen]
567//!    fn update(&mut self) {
568//!       self.sig3.next = self.sig1.val() + 4; // Example of binop with a literal
569//!       self.sig3.next = self.sig1.val() ^ self.sig2.val(); // Example of a binop with two bitvecs
570//!    }
571//! }
572//! ```
573//!
574//! - Unary operations supported are `-` and `!`
575//! The `-` operator is only supported for `Signed` types.  Otherwise, it makes no sense.  If
576//! you want to compute the 2's complement of an unsigned value, you need to do so explicitly.
577//! The `!` operator will flip all of the bits in the bitvector.
578//! - Conditionals (`if`) are supported
579//!```rust
580//! # use rust_hdl::prelude::*;
581//!
582//! struct Foo {
583//!     pub sig1: Signal<In, Bit>,
584//!     pub sig2: Signal<Out, Bits<2>>,
585//!     pub sig3: Signal<In, Bits<2>>,
586//!     pub sig4: Signal<Out, Bits<2>>,
587//! }
588//!
589//! impl Logic for Foo {
590//!     #[hdl_gen]
591//!     fn update(&mut self) {
592//!         self.sig2.next = 0.into(); // Latch prevention!
593//!         // Straight `if`s are supported, but beware of latches!
594//!         // This `if` statement would generate a latch if not for
595//!         // the unconditional assign to `sig2`
596//!         if self.sig1.val() {
597//!            self.sig2.next = 1.into();
598//!         }
599//!         // You can use `else` clauses also
600//!         if self.sig1.val() {
601//!            self.sig2.next = 1.into();
602//!         } else {
603//!            self.sig2.next = 2.into();
604//!         }
605//!         // Nesting and chaining are also fine
606//!         if self.sig3.val() == 0 {
607//!            self.sig4.next = 3.into();
608//!         } else if self.sig3.val() == 1 {
609//!            self.sig4.next = 2.into();
610//!         } else {
611//!            self.sig4.next = 0.into();   // <- Fall through else prevents latch
612//!         }
613//!     }
614//! }
615//! ```
616//! - Literals (provided they implement the `Synth` trait) are supported.  In most cases, you
617//! can used un-suffixed literals (like `1` or `0xDEAD`) as add `.into()`.
618//! - Function calls - RustHDL kernels support a very limited number of function calls, all of
619//!    which are ignored in HDL at the moment (they are provided to make `rustc` happy)
620//!     - `bit_cast`
621//!     - `signed_bit_cast`
622//!     - `unsigned_cast`
623//!     - `bits`
624//!     - `Bits`
625//!     - `Type::join` and `Type::link` used to link and join logical interfaces...
626//! - Method calls - Kernels support the following limited set of method calls
627//!     - `get_bits` - extract a (fixed width) set of bits from a bit vector
628//!     - `get_bit` - extract a single bit from a bit vector
629//!     - `replace_bit` - replace a single bit in a bit vector
630//!     - `all` - true if all the bits in the bit vector are true
631//!     - `any` - true if any of the bits in the bit vector are true
632//!     - `xor` - true if the number of ones in the bit vector is odd
633//!     - `val`, `into`, `index`, `to_bits` - ignored in HDL kernels
634//! ```rust
635//! # use rust_hdl::prelude::*;
636//!
637//! struct Foo {
638//!     pub sig1: Signal<In, Bits<8>>,
639//!     pub sig_index: Signal<In, Bits<3>>,
640//!     pub sig2: Signal<Out, Bit>,
641//!     pub sig3: Signal<Out, Bits<3>>,
642//!     pub sig4: Signal<Out, Bit>,
643//! }
644//!
645//! impl Logic for Foo {
646//!     #[hdl_gen]
647//!     fn update(&mut self) {
648//!         self.sig2.next = self.sig1.val().get_bit(self.sig_index.val().index()); // <- Selects specified bit out of sig1
649//!         self.sig3.next = self.sig1.val().get_bits::<3>(self.sig_index.val().index()); // Selects 3 bits starting at index `sig_index`
650//!         // Notice that here we have an output on both the left and right side of the assignment
651//!         // That is fine as long we we write to `.next` before we read from `.val`.
652//!         self.sig4.next = self.sig3.val().all(); // True if sig3 is all true
653//!     }
654//! }
655//! ```
656//! - Matches - Kernels support matching with literals or identifiers
657//! Matches are used for state machines and implementing ROMs.  
658//! For now, `match` is a statement, not an expression!  Maybe that will be fixed in a future
659//! version of RustHDL, but for now, the value of the `match` is ignored.
660//! Here is an example of a `match` for a state machine:
661//! ```rust
662//! # use rust_hdl::prelude::*;
663//! # use rust_hdl::widgets::prelude::*;
664//!
665//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
666//! enum State {
667//!     Idle,
668//!     Running,
669//!     Paused,
670//! }
671//!
672//!
673//! struct Foo {
674//!     pub start: Signal<In, Bit>,
675//!     pub pause: Signal<In, Bit>,
676//!     pub stop: Signal<In, Bit>,
677//!     pub clock: Signal<In, Clock>,
678//!     state: DFF<State>,
679//! }
680//!
681//! impl Logic for Foo {
682//!     #[hdl_gen]
683//!     fn update(&mut self) {
684//!        dff_setup!(self, clock, state); // <- setup the DFF
685//!        match self.state.q.val() {
686//!            State::Idle =>
687//!                   if self.start.val() {
688//!                      self.state.d.next = State::Running;
689//!                   }
690//!            State::Running =>
691//!                   if self.pause.val() {
692//!                      self.state.d.next = State::Paused;
693//!                   }
694//!            State::Paused =>
695//!                   if !self.pause.val() {
696//!                      self.state.d.next = State::Running;
697//!                   }
698//!        }
699//!        if self.stop.val() {
700//!            self.state.d.next = State::Idle;
701//!        }
702//!     }
703//! }
704//! ```
705//! - Macros - some macros are supported in kernels
706//!     - `println` - this is converted into a comment in the generated HDL
707//!     - `comment` - also a comment
708//!     - `assert` - converted to a comment
709//!     - `dff_setup` - setup a DFF - this macro is converted into the appropriate HDL
710//!     - `clock` - clock a set of components - this macro is also converted into the appropriate HDL
711//! - Loops - `for` loops are supported for code generation
712//!     - In software parlance, all `for` loops are unrolled at compile time, so they must be of the form `for <ident> in <const>..<const>`.
713//! A simple example to consider is a parameterizable mux.
714//!
715//! ```rust
716//! # use rust_hdl::prelude::*;
717//!
718//! // Mux from N separate signals, using A address bits
719//! // For fun, it's also generic over the width of the
720//! // signals being muxed.  So there are 3 generics here:
721//! //    - D - the type of those signals
722//! //    - N - the number of signals being muxed
723//! //    - A - the number of address bits (check that 2^A >= N)
724//! struct Mux<D: Synth, const N: usize, const A: usize> {
725//!    pub input_lines: [Signal<In, D>; N],
726//!    pub select: Signal<In, Bits<A>>,
727//!    pub outsig: Signal<Out, D>,
728//!    fallback: Constant<D>,
729//! }
730//!
731//! // The impl for this requires a for loop
732//! impl<D: Synth, const N: usize, const A: usize> Logic for Mux<D, N, A> {
733//!   #[hdl_gen]
734//!   fn update(&mut self) {
735//!        self.outsig.next = self.fallback.val();
736//!        for i in 0..N {
737//!           if self.select.val().index() == i {
738//!              self.outsig.next = self.input_lines[i].val();
739//!           }
740//!        }
741//!    }
742//! }
743//! ```
744//! RustHDL is still pretty restrictive about arrays and loops.  You can still do great stuff though.
745//!
746//! Since an example is instructive, here is the HDL kernel for a nontrivial circuit (the `SPIMaster`),
747//! annotated to demonstrate the various valid bits of syntax.  It's been heavily redacted to make
748//! it easier to read.
749//!
750//! ```
751//! # use rust_hdl::prelude::*;
752//! # use rust_hdl::widgets::prelude::*;
753//!# #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
754//!# enum SPIState {
755//!#     Idle,
756//!#     Dwell,
757//!#     LoadBit,
758//!#     MActive,
759//!#     SampleMISO,
760//!#     MIdle,
761//!#     Finish,
762//!# }
763//!# #[derive(Copy, Clone)]
764//!# pub struct SPIConfig {
765//!#     pub clock_speed: u64,
766//!#     pub cs_off: bool,
767//!#     pub mosi_off: bool,
768//!#     pub speed_hz: u64,
769//!#     pub cpha: bool,
770//!#     pub cpol: bool,
771//!# }
772//!# #[derive(LogicInterface, Default)]
773//!# #[join = "SPIWiresSlave"]
774//!# pub struct SPIWiresMaster {
775//!#     pub mosi: Signal<Out, Bit>,
776//!#     pub miso: Signal<In, Bit>,
777//!#     pub msel: Signal<Out, Bit>,
778//!#     pub mclk: Signal<Out, Bit>,
779//!# }
780//!# #[derive(LogicInterface, Default)]
781//!# #[join = "SPIWiresMaster"]
782//!# pub struct SPIWiresSlave {
783//!#     pub mosi: Signal<In, Bit>,
784//!#     pub miso: Signal<Out, Bit>,
785//!#     pub msel: Signal<In, Bit>,
786//!#     pub mclk: Signal<In, Bit>,
787//!# }
788//! // Note - you can use const generics in HDL definitions and kernels!
789//! #[derive(LogicBlock)]
790//! struct SPIMaster<const N: usize> {
791//!     // The `pub` members are the ones you can access from other circuits.
792//!     // These form the official interface of the circuit
793//!     pub clock: Signal<In, Clock>,
794//!     pub bits_outbound: Signal<In, Bits<16>>,
795//!     pub data_outbound: Signal<In, Bits<N>>,
796//!     // snip...
797//!#     pub data_inbound: Signal<Out, Bits<N>>,
798//!#     pub start_send: Signal<In, Bit>,
799//!#     pub transfer_done: Signal<Out, Bit>,
800//!#     pub continued_transaction: Signal<In, Bit>,
801//!#     pub busy: Signal<Out, Bit>,
802//!#     pub wires: SPIWiresMaster,   // <-- This is a LogicInterface type
803//!     // These are private, so they can only be accessed by internal code
804//!     register_out: DFF<Bits<N>>,
805//!     register_in: DFF<Bits<N>>,
806//!     state: DFF<SPIState>,
807//!     strobe: Strobe<32>,
808//!     pointer: DFF<Bits<16>>,
809//!      // snip...
810//!#     pointerm1: Signal<Local, Bits<16>>,
811//!#     clock_state: DFF<Bit>,
812//!#     done_flop: DFF<Bit>,
813//!#     msel_flop: DFFWithInit<Bit>,
814//!#     mosi_flop: DFF<Bit>,
815//!#     continued_save: DFF<Bit>,
816//!     // Computed constants need to be stored in a special Constant field member
817//!     cs_off: Constant<Bit>,
818//!     mosi_off: Constant<Bit>,
819//!#     cpha: Constant<Bit>,
820//!#     cpol: Constant<Bit>,
821//! }
822//!
823//!impl<const N: usize> Logic for SPIMaster<N> {
824//!     #[hdl_gen]
825//!     fn update(&mut self) {
826//!         // Setup the internals - for Latch avoidance, each digital flip flop
827//!         // requires setup - it needs to be clocked, and it needs to connect
828//!         // the output and input together, so that the input is driven.
829//!         // This macro simply declutters the code a bit and makes it easier to read.
830//!         dff_setup!(
831//!             self,
832//!             clock,
833//!             //   | equivalent to `self.register_out.clock.next = self.clock.val();`
834//!             // v--               `self.register_out.d.next = self.register_out.q.val();`
835//!             register_out,
836//!             register_in,
837//!             state,
838//!             pointer,
839//!#             clock_state,
840//!#             done_flop,
841//!#             msel_flop,
842//!#             mosi_flop,
843//!#             continued_save
844//!         );
845//!         // This macro is shorthand for `self.strobe.next = self.clock.val();`
846//!         clock!(self, clock, strobe);
847//!         // These are just standard assignments... Nothing too special.
848//!         // Note that `.next` is on the LHS, and `.val()` on the right...
849//!         self.strobe.enable.next = true;
850//!         self.wires.mclk.next = self.clock_state.q.val();
851//!#         self.wires.mosi.next = self.mosi_flop.q.val();
852//!         self.wires.msel.next = self.msel_flop.q.val();
853//!         self.data_inbound.next = self.register_in.q.val();
854//!#         self.transfer_done.next = self.done_flop.q.val();
855//!#         self.done_flop.d.next = false;
856//!         self.pointerm1.next = self.pointer.q.val() - 1;
857//!#         self.busy.next = true;
858//!         // The `match` is used to model state machines
859//!         match self.state.q.val() {
860//!             SPIState::Idle => {
861//!                 self.busy.next = false;
862//!                 self.clock_state.d.next = self.cpol.val();
863//!                 if self.start_send.val() {
864//!                     // Capture the outgoing data in our register
865//!                     self.register_out.d.next = self.data_outbound.val();
866//!                     self.state.d.next = SPIState::Dwell; // Transition to the DWELL state
867//!                     self.pointer.d.next = self.bits_outbound.val(); // set bit pointer to number of bit to send (1 based)
868//!                     self.register_in.d.next = 0.into(); // Clear out the input store register
869//!                     self.msel_flop.d.next = !self.cs_off.val(); // Activate the chip select
870//!                     self.continued_save.d.next = self.continued_transaction.val();
871//!                 } else {
872//!                     if !self.continued_save.q.val() {
873//!                         self.msel_flop.d.next = self.cs_off.val(); // Set the chip select signal to be "off"
874//!                     }
875//!                 }
876//!                 self.mosi_flop.d.next = self.mosi_off.val(); // Set the mosi signal to be "off"
877//!             }
878//!             SPIState::Dwell => {
879//!                 if self.strobe.strobe.val() {
880//!                     // Dwell timeout has reached zero
881//!                     self.state.d.next = SPIState::LoadBit; // Transition to the loadbit state
882//!                 }
883//!             }
884//!             SPIState::LoadBit => {
885//!                 // Note in this statement that to use the pointer register as a bit index
886//!                 // into the `register_out` DFF, we need to convert it with `index()`.
887//!                 if self.pointer.q.val().any() {
888//!                     // We have data to send
889//!                     self.mosi_flop.d.next = self
890//!                         .register_out
891//!                         .q
892//!                         .val()
893//!                         .get_bit(self.pointerm1.val().index()); // Fetch the corresponding bit out of the register
894//!#                     self.pointer.d.next = self.pointerm1.val(); // Decrement the pointer
895//!                     self.state.d.next = SPIState::MActive; // Move to the hold mclock low state
896//!                     self.clock_state.d.next = self.cpol.val() ^ self.cpha.val();
897//!                 } else {
898//!                     self.mosi_flop.d.next = self.mosi_off.val(); // Set the mosi signal to be "off"
899//!                     self.clock_state.d.next = self.cpol.val();
900//!                     self.state.d.next = SPIState::Finish; // No data, go back to idle
901//!                 }
902//!             }
903//!             SPIState::MActive => {
904//!                 if self.strobe.strobe.val() {
905//!                     self.state.d.next = SPIState::SampleMISO;
906//!                 }
907//!             }
908//!#           SPIState::SampleMISO => {}
909//!#           SPIState::MIdle => {}
910//!#           SPIState::Finish => {}
911//!        }
912//!     }
913//!}
914//! ```
915//!
916//! ## Enums
917//!
918//! In keeping with Rust's strongly typed model, you can use enums (not sum types) in your HDL,
919//! provided you derive the `LogicState` trait for them.  This makes your code much easier to
920//! read and debug, and `rustc` will make sure you don't do anything illegal with your
921//! enums.
922//!  
923//! ```rust
924//! # use rust_hdl::prelude::*;
925//!
926//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
927//! enum State {
928//!     Idle,
929//!     Running,
930//!     Paused,
931//! }
932//! ```
933//!
934//! Using enums for storing things like state has several advantages:
935//! - RustHDL will automatically calculate the minimum number of bits needed to store the
936//! enum in e.g., a register.
937//!
938//! For example, we can create a Digital Flip Flop (register) of value `State` from the next
939//! example, and RustHDL will convert this into a 2 bit binary register.  
940//!
941//! ```rust
942//! # use rust_hdl::prelude::*;
943//! # use rust_hdl::widgets::prelude::*;
944//!
945//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
946//! enum State {
947//!     Idle,
948//!     Sending,
949//!     Receiving,
950//!     Done,
951//! }
952//!
953//! struct Foo {
954//!     dff: DFF<State>,  // <-- This is a 2 bit DFF
955//! }
956//! ```
957//!
958//! Now imagine we add another state in the future to our state machine - say `Pending`:
959//!
960//! ```rust
961//! # use rust_hdl::prelude::*;
962//! # use rust_hdl::widgets::prelude::*;
963//!
964//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
965//! enum State {
966//!     Idle,
967//!     Sending,
968//!     Receiving,
969//!     Pending,
970//!     Done,
971//! }
972//!
973//! struct Foo {
974//!     dff: DFF<State>,  // <-- This is now a 3 bit DFF!
975//! }
976//! ```
977//! RustHDL will _automatically_ choose a 3-bit representation.  
978//!
979//! - RustHDL will ensure that assignments to `enum`-valued signals are valid at all times
980//!
981//! The strong type guarantees ensure you cannot assign arbitrary values to `enum` valued
982//! signals, and the namespaces ensure that there is no ambiguity in assignment.  This example
983//! won't compile, since `On` without the name of the `enum` means nothing, and `State1` and
984//! `State2` are separate types.  They cannot be assigned to one another.
985//!
986//! ```compile_fail
987//! # use rust_hdl::prelude::*;
988//!
989//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
990//! enum State1 {
991//!      On,
992//!      Off,
993//! }
994//!
995//! #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
996//! enum State2 {
997//!      Off,
998//!      On,
999//! }
1000//!
1001//! struct Foo {
1002//!     pub sig_in: Signal<In, State1>,
1003//!     pub sig_out: Signal<Out, State2>,
1004//! }
1005//!
1006//! impl Logic for Foo {
1007//!     #[hdl_gen]
1008//!     fn update(&mut self) {
1009//!         self.sig_out.next = On; // << This won't work either.
1010//!         self.sig_out.next = self.sig_in.val(); // << Won't compile
1011//!     }
1012//! }
1013//! ```
1014//!
1015//! If for some reason, you needed to translate between enums, use a `match`:
1016//!
1017//! ```rust
1018//! # use rust_hdl::prelude::*;
1019//!
1020//! # #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
1021//! # enum State1 {
1022//! #     On,
1023//! #     Off,
1024//! # }
1025//! # #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
1026//! # enum State2 {
1027//! #     Off,
1028//! #     On,
1029//! # }
1030//! #
1031//! # struct Foo {
1032//! #     pub sig_in: Signal<In, State1>,
1033//! #     pub sig_out: Signal<Out, State2>,
1034//! # }
1035//! #
1036//! impl Logic for Foo {
1037//!    #[hdl_gen]
1038//!    fn update(&mut self) {
1039//!       match self.sig_in.val() {
1040//!           State1::On => self.sig_out.next = State2::On,
1041//!           State1::Off => self.sig_out.next = State2::Off,
1042//!       }
1043//!    }
1044//! }
1045//! ```
1046//!
1047//! ## Interfaces
1048//!
1049//! One area you will encouter as your circuits become more complex is that the interfaces
1050//! to those circuits will become increasingly complicated.  To demonstrate, suppose you
1051//! have a circuit that consumes a sequence of 16-bit integers via a FIFO interface.  The
1052//! circuit has some flow control signals because it cannot consume them every clock
1053//! cycle (For Reasons).  Suppose also that you have a data producer circuit that will
1054//! produce 16-bit integers and you want to connect these two together.  A natural
1055//! FIFO interface would look like this
1056//!
1057//! ```rust
1058//!# use rust_hdl::prelude::*;
1059//!  struct MyFIFO {
1060//!      pub data_to_fifo: Signal<In, Bits<16>>,
1061//!      pub write: Signal<In, Bits<16>>,
1062//!      pub full: Signal<Out, Bit>,
1063//!      pub overflow: Signal<Out, Bit>,
1064//!  }
1065//!
1066//!  struct DataWidget {
1067//!      pub data_to_fifo: Signal<Out, Bits<16>>,
1068//!      pub write: Signal<Out, Bits<16>>,
1069//!      pub full: Signal<In, Bit>,
1070//!      pub overflow: Signal<In, Bit>,
1071//!  }
1072//!
1073//!  struct Foo {
1074//!     producer: DataWidget,
1075//!     consumer: MyFIFO,
1076//!  }
1077//! ```
1078//!
1079//! Now, we want to connect the output of the DataWidget (all 4 signals!) to the corresponding
1080//! signals on `MyFIFO`.  Keep in mind that the order of assignment is irrelevant, but which
1081//! signal appears on the LHS vs RHS _is_ important.  In the `impl Logic` block for `Foo`,
1082//! our HDL kernel will look like this:
1083//!```rust
1084//!# use rust_hdl::prelude::*;
1085//!#  struct MyFIFO {
1086//!#      pub data_to_fifo: Signal<In, Bits<16>>,
1087//!#      pub write: Signal<In, Bits<16>>,
1088//!#      pub full: Signal<Out, Bit>,
1089//!#      pub overflow: Signal<Out, Bit>,
1090//!#  }
1091//!#
1092//!#  struct DataWidget {
1093//!#      pub data_to_fifo: Signal<Out, Bits<16>>,
1094//!#      pub write: Signal<Out, Bits<16>>,
1095//!#      pub full: Signal<In, Bit>,
1096//!#      pub overflow: Signal<In, Bit>,
1097//!#  }
1098//!#
1099//!#  struct Foo {
1100//!#     producer: DataWidget,
1101//!#     consumer: MyFIFO,
1102//!#  }
1103//!impl Logic for Foo {
1104//!   #[hdl_gen]
1105//!   fn update(&mut self) {
1106//!      self.consumer.data_to_fifo.next = self.producer.data_to_fifo.val();
1107//!      self.consumer.write.next = self.producer.write.val();
1108//!      self.producer.full.next = self.consumer.full.val();
1109//!      self.producer.overflow.next = self.consumer.overflow.val();
1110//!   }
1111//!}
1112//!```
1113//! This is basically boilerplate at this point, and typing that in and getting it right
1114//! is error prone and tedious.  Fortunately, RustHDL can help!  RustHDL includes the
1115//! concept of an `Interface`, which is basically a bus.  An `Interface` is generally a
1116//! pair of structs that contain signals of complementary directions and a `#[derive]`
1117//! macro that autogenerates a bunch of boilerplate.  To continue on with our previous
1118//! example, we could define a pair of `struct`s for the write interface of the FIFO
1119//!
1120//! ```rust
1121//! # use rust_hdl::prelude::*;
1122//! #[derive(LogicInterface)]     // <- Note the LogicInterface, not LogicBlock
1123//! #[join = "MyFIFOWriteSender"] // <- Name of the "mating" interface
1124//! struct MyFIFOWriteReceiver {
1125//!     pub data_to_fifo: Signal<In, Bits<16>>,
1126//!     pub write: Signal<In, Bit>,
1127//!     pub full: Signal<Out, Bit>,
1128//!     pub overflow: Signal<Out, Bit>,
1129//! }
1130//!
1131//! #[derive(LogicInterface)]       // <- Also here
1132//! #[join = "MyFIFOWriteReceiver"] // <- Name of the "mating" interface
1133//! struct MyFIFOWriteSender {
1134//!    pub data_to_fifo: Signal<Out, Bits<16>>,
1135//!    pub write: Signal<Out, Bit>,
1136//!    pub full: Signal<In, Bit>,
1137//!    pub overflow: Signal<In, Bit>
1138//! }
1139//! ```
1140//!The names of the fields must match, the types of the fields must also match, and the directions
1141//! of the signals must be complementary.  So in general:
1142//!
1143//! - Each field in struct `A` must have a matching named field in struct `B`
1144//! - The types of those fields must match
1145//! - The direction of those signals must be opposite
1146//! - Order of the fields is immaterial
1147//! - The `join` attribute tells the compiler which interface to mate to this one.
1148//!
1149//! So what can we do with our shiny new interfaces?  Plenty of stuff.  First, lets
1150//! rewrite our FIFO circuit and data producer to use our new interfaces.
1151//!
1152//! ```rust
1153//! # use rust_hdl::prelude::*;
1154//!#  #[derive(LogicInterface)]     // <- Note the LogicInterface, not LogicBlock
1155//!#  #[join = "MyFIFOWriteSender"] // <- Name of the "mating" interface
1156//!#  struct MyFIFOWriteReceiver {
1157//!#      pub data_to_fifo: Signal<In, Bits<16>>,
1158//!#      pub write: Signal<In, Bit>,
1159//!#      pub full: Signal<Out, Bit>,
1160//!#      pub overflow: Signal<Out, Bit>,
1161//!#  }
1162//!#  #[derive(LogicInterface)]       // <- Also here
1163//!#  #[join = "MyFIFOWriteReceiver"] // <- Name of the "mating" interface
1164//!#  struct MyFIFOWriteSender {
1165//!#     pub data_to_fifo: Signal<Out, Bits<16>>,
1166//!#     pub write: Signal<Out, Bit>,
1167//!#     pub full: Signal<In, Bit>,
1168//!#     pub overflow: Signal<In, Bit>
1169//!#  }
1170//! struct MyFIFO {
1171//!     // The write interface to the FIFO - now only one line!
1172//!     pub write_bus: MyFIFOWriteReceiver,
1173//! }
1174//!
1175//! struct DataWidget {
1176//!     // The output interface from the DataWidget!
1177//!     pub data_out: MyFIFOWriteSender,
1178//! }
1179//! ```
1180//!
1181//! That is significantly less verbose!  So what happens to our
1182//! `impl Logic for Foo`?  Well, RustHDL autogenerates 2 methods for each `LogicInterface`.  The first
1183//! one is called `join`.  And it, well, joins the interfaces.
1184//!
1185//! ```rust
1186//! # use rust_hdl::prelude::*;
1187//!#  #[derive(LogicInterface)]     // <- Note the LogicInterface, not LogicBlock
1188//!#  #[join = "MyFIFOWriteSender"] // <- Name of the "mating" interface
1189//!#  struct MyFIFOWriteReceiver {
1190//!#      pub data_to_fifo: Signal<In, Bits<16>>,
1191//!#      pub write: Signal<In, Bit>,
1192//!#      pub full: Signal<Out, Bit>,
1193//!#      pub overflow: Signal<Out, Bit>,
1194//!#  }
1195//!#  #[derive(LogicInterface)]       // <- Also here
1196//!#  #[join = "MyFIFOWriteReceiver"] // <- Name of the "mating" interface
1197//!#  struct MyFIFOWriteSender {
1198//!#     pub data_to_fifo: Signal<Out, Bits<16>>,
1199//!#     pub write: Signal<Out, Bit>,
1200//!#     pub full: Signal<In, Bit>,
1201//!#     pub overflow: Signal<In, Bit>
1202//!#  }
1203//!#  struct MyFIFO {
1204//!#      // The write interface to the FIFO - now only one line!
1205//!#      pub write_bus: MyFIFOWriteReceiver,
1206//!#  }
1207//!#  struct DataWidget {
1208//!#      pub data_out: MyFIFOWriteSender,
1209//!#  }
1210//!#  struct Foo {
1211//!#     producer: DataWidget,
1212//!#     consumer: MyFIFO,
1213//!#  }
1214//! impl Logic for Foo {
1215//!    #[hdl_gen]
1216//!    fn update(&mut self) {
1217//!       // Excess verbosity eliminated!!
1218//!       MyFIFOWriteSender::join(&mut self.producer.data_out, &mut self.consumer.write_bus);
1219//!    }
1220//! }
1221//! ```
1222//!
1223//! This is exactly equivalent to our previous 4 lines of hand crafted code, but is now automatically
1224//! generated _and_ synthesizable.  But wait!  There is more.  RustHDL also generates a `link`
1225//! method, which allows you to _forward_ a bus from one point to another.  If you think in terms
1226//! gendered cables, a `join` is a cable with a Male connector on one end and a Female connector
1227//! on the other.  A `link` is a cable that is either Male to Male or Female to Female.  Links
1228//! are useful when you want to forward an interface to an interior component of a circuit, but
1229//! hide that interior component from the outside world.  For example, lets suppose that
1230//! `DataWidget` doesn't actually produce the 16-bit samples.  Instead, some other FPGA component
1231//! or circuit generates the 16-bit samples, and `DataWidget` just wraps it along with some
1232//! other control logic.  So in fact, our `DataWidget` has an internal representation that looks
1233//! like this
1234//!```rust
1235//! # use rust_hdl::prelude::*;
1236//! # use rust_hdl::widgets::prelude::*;
1237//! # struct MyFIFOWriteSender{}
1238//! struct DataWidget {
1239//!    pub data_out: MyFIFOWriteSender,
1240//!    secret_guy: CryptoGenerator,
1241//!    running: DFF<Bit>,
1242//! }
1243//!
1244//! struct CryptoGenerator {
1245//!    pub data_out: MyFIFOWriteSender,
1246//!    // secret stuff!
1247//! }
1248//!```  
1249//!
1250//! In this example, the `DataWidget` wants to present the outside world that it is a `MyFIFOWriteSender`
1251//! interface, and that it can produce 16-bit data values.  But the real work is being done internally
1252//! by the `secret_guy`.  The manual way to do this would be to connect up the signals manually.  Again,
1253//! paying attention to which signal is an input (for `DataWidget`), and which is an output.
1254//!
1255//! ```rust
1256//! # use rust_hdl::prelude::*;
1257//! # use rust_hdl::widgets::prelude::*;
1258//!#  #[derive(LogicInterface)]     // <- Note the LogicInterface, not LogicBlock
1259//!#  #[join = "MyFIFOWriteSender"] // <- Name of the "mating" interface
1260//!#  struct MyFIFOWriteReceiver {
1261//!#      pub data_to_fifo: Signal<In, Bits<16>>,
1262//!#      pub write: Signal<In, Bit>,
1263//!#      pub full: Signal<Out, Bit>,
1264//!#      pub overflow: Signal<Out, Bit>,
1265//!#  }
1266//!#  #[derive(LogicInterface)]       // <- Also here
1267//!#  #[join = "MyFIFOWriteReceiver"] // <- Name of the "mating" interface
1268//!#  struct MyFIFOWriteSender {
1269//!#     pub data_to_fifo: Signal<Out, Bits<16>>,
1270//!#     pub write: Signal<Out, Bit>,
1271//!#     pub full: Signal<In, Bit>,
1272//!#     pub overflow: Signal<In, Bit>
1273//!#  }
1274//!#  struct DataWidget {
1275//!#     pub data_out: MyFIFOWriteSender,
1276//!#     secret_guy: CryptoGenerator,
1277//!#     running: DFF<Bit>,
1278//!#  }
1279//!#  struct CryptoGenerator {
1280//!#     pub data_out: MyFIFOWriteSender,
1281//!#     // secret stuff!
1282//!#  }
1283//! impl Logic for DataWidget {
1284//!    #[hdl_gen]
1285//!     fn update(&mut self) {
1286//!        // Yawn...
1287//!        self.data_out.data_to_fifo.next = self.secret_guy.data_out.data_to_fifo.val();
1288//!        self.data_out.write.next = self.secret_guy.data_out.write.val();
1289//!        self.secret_guy.data_out.full.next = self.data_out.full.val();
1290//!        self.secret_guy.data_out.overflow.next = self.data_out.overflow.val();
1291//!     }
1292//! }
1293//! ```
1294//!
1295//! In these instances, you can use the `link` method instead.  The syntax is
1296//! `Interface::link(&mut self.outside, &mut self.inside)`, where `outside` is the
1297//! side of the interface going out of the circuit, and `inside` is the side of the interface
1298//! inside of the circuit.  Hence, our interface can be `forwarded` or `linked` with a single line
1299//! like so:
1300//! ```rust
1301//! # use rust_hdl::prelude::*;
1302//! # use rust_hdl::widgets::prelude::*;
1303//!#  #[derive(LogicInterface)]     // <- Note the LogicInterface, not LogicBlock
1304//!#  #[join = "MyFIFOWriteSender"] // <- Name of the "mating" interface
1305//!#  struct MyFIFOWriteReceiver {
1306//!#      pub data_to_fifo: Signal<In, Bits<16>>,
1307//!#      pub write: Signal<In, Bit>,
1308//!#      pub full: Signal<Out, Bit>,
1309//!#      pub overflow: Signal<Out, Bit>,
1310//!#  }
1311//!#  #[derive(LogicInterface)]       // <- Also here
1312//!#  #[join = "MyFIFOWriteReceiver"] // <- Name of the "mating" interface
1313//!#  struct MyFIFOWriteSender {
1314//!#     pub data_to_fifo: Signal<Out, Bits<16>>,
1315//!#     pub write: Signal<Out, Bit>,
1316//!#     pub full: Signal<In, Bit>,
1317//!#     pub overflow: Signal<In, Bit>
1318//!#  }
1319//!#  struct DataWidget {
1320//!#     pub data_out: MyFIFOWriteSender,
1321//!#     secret_guy: CryptoGenerator,
1322//!#     running: DFF<Bit>,
1323//!#  }
1324//!#  struct CryptoGenerator {
1325//!#     pub data_out: MyFIFOWriteSender,
1326//!#     // secret stuff!
1327//!#  }
1328//! impl Logic for DataWidget {
1329//!    #[hdl_gen]
1330//!     fn update(&mut self) {
1331//!        // Tada!
1332//!        MyFIFOWriteSender::link(&mut self.data_out, &mut self.secret_guy.data_out);
1333//!     }
1334//! }
1335//! ```
1336//!
1337//! As a parting note, you can make interfaces generic across types.  Here, for example
1338//! is the FIFO interface used in the High Level Synthesis library in RustHDL:
1339//! ```rust
1340//! # use rust_hdl::prelude::*;
1341//!#[derive(Clone, Debug, Default, LogicInterface)]
1342//! #[join = "FIFOWriteResponder"]
1343//! pub struct FIFOWriteController<T: Synth> {
1344//!     pub data: Signal<Out, T>,
1345//!     pub write: Signal<Out, Bit>,
1346//!     pub full: Signal<In, Bit>,
1347//!     pub almost_full: Signal<In, Bit>,
1348//! }
1349//!
1350//! #[derive(Clone, Debug, Default, LogicInterface)]
1351//! #[join = "FIFOWriteController"]
1352//! pub struct FIFOWriteResponder<T: Synth> {
1353//!     pub data: Signal<In, T>,
1354//!     pub write: Signal<In, Bit>,
1355//!     pub full: Signal<Out, Bit>,
1356//!     pub almost_full: Signal<Out, Bit>,
1357//! }
1358//! ```
1359//!
1360//! You can then use any synthesizable type for the data bus, and keep the control signals
1361//! as single bits!  Neat, eh? 🦑
1362//!
1363//! ## Simulation
1364//!
1365//! Now that you have a shiny new circuit implemented as a struct, what do you do with it?
1366//! Typically, in hardware design, the first thing you do (after static analysis) is to simulate
1367//! the circuit.  Simulation allows you to verify the proper behavior of the circuit in software
1368//! _before_ heading over to the bench to test on the physical hardware.  There is a saying
1369//! in hardware design "success in simulation is necessary, but not sufficient for correct operation".
1370//! Or something like that.
1371//!
1372//! In any case, RustHDL makes it easy to simulate your designs by allowing you to create and write
1373//! complex test benches in Rust instead of in an HDL like Verilog or VHDL.  Furthermore, the
1374//! simulator is built in, so you do not need to use external tools for simulation.  Occasionally,
1375//! you may need to or want to simulate using external tools.  Currently, RustHDL can't help
1376//! much there.  You can convert your design to Verilog and then import it into standard
1377//! simulation tools, but the testbench won't go with the design.  Maybe in the future...
1378//!
1379//! The simulator that is built into RustHDL is pretty basic, and easy to use.  To use it, you
1380//! need a circuit to simulate.  Let's create a basic 8 bit adder with a clocked register for
1381//! the output (and no carry):
1382//! ```rust
1383//! use rust_hdl::prelude::*;   // <- shorthand to bring in all definitions
1384//!
1385//! //        v--- Required by RustHDL
1386//! #[derive(LogicBlock, Default)]
1387//! struct MyAdder {
1388//!     pub sig_a: Signal<In, Bits<8>>,
1389//!     pub sig_b: Signal<In, Bits<8>>,
1390//!     pub sig_sum: Signal<Out, Bits<8>>,
1391//!     pub clock: Signal<In, Clock>,
1392//!     my_reg: DFF<Bits<8>>,
1393//! }
1394//!
1395//! impl Logic for MyAdder {
1396//!   #[hdl_gen]  // <--- don't forget this
1397//!   fn update(&mut self) {
1398//!        // Setup the DFF.. this macro is handy to prevent latches
1399//!        dff_setup!(self, clock, my_reg);
1400//!        self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
1401//!        self.sig_sum.next = self.my_reg.q.val();
1402//!    }
1403//! }
1404//! ```
1405//!
1406//! At this point, we can convert `MyAdder` into Verilog and use a standard toolchain to generate
1407//! a bitfile.  However, we want to verify that the circuit operates properly.   The simplest way
1408//! to do that would be to feed it a vector of random inputs, and make sure that the output
1409//! matches the sum of the inputs.  Setting up a simulation can be a little verbose, so there
1410//! is a handy macro [simple_sim!] that works if you have only a single (top level) clock,
1411//! and only need one test bench.
1412//!
1413//! ** An aside on ownership **
1414//! We haven't talked about the borrow checker much.  And that is because by and large, RustHDL
1415//! does not use references.  So how do the testbenches work?  The key points for those of you
1416//! familiar with Rust are:
1417//!    - The circuit must be [Send].  All RustHDL components are [Send].
1418//!    - The simulation uses a [Box] to hold the circuit.
1419//!    - Each testbench runs in it's own thread.
1420//!    - The circuit is moved to each testbench as it runs via the endpoint.
1421//!    - The testbench then updates the circuit inputs, and checks outputs.  It is the
1422//!      sole owner of the circuit at this point.  
1423//!    - The techbench then passes the circuit back to the simulation (moves) along with some
1424//!      indication of when it needs to see it again.
1425//!    - If a testbench is complete, it signals that it does not need to see the circuit again.
1426//!    - When all testbenches are complete (or any of them report an error), the simulation
1427//!      halts.
1428//!
1429//! It takes a little getting used to, but the design allows you to write concurrent testbenches
1430//! without worrying about shared mutable state.
1431//!
1432//! So back to our adder.  The testbench should look something like this
1433//!  - set input A to some known value x
1434//!  - set input B to some known value y
1435//!  - wait a clock cycle
1436//!  - check that the output matches the sum x + y
1437//!  - loop until complete.
1438//!
1439//! Here is a complete example:
1440//! ```rust
1441//!# use rust_hdl::prelude::*;   // <- shorthand to bring in all definitions
1442//!#
1443//!# //        v--- Required by RustHDL
1444//!# #[derive(LogicBlock, Default)]
1445//!# struct MyAdder {
1446//!#     pub sig_a: Signal<In, Bits<8>>,
1447//!#     pub sig_b: Signal<In, Bits<8>>,
1448//!#     pub sig_sum: Signal<Out, Bits<8>>,
1449//!#     pub clock: Signal<In, Clock>,
1450//!#     my_reg: DFF<Bits<8>>,
1451//!# }
1452//!#
1453//!# impl Logic for MyAdder {
1454//!#   #[hdl_gen]  // <--- don't forget this
1455//!#   fn update(&mut self) {
1456//!#        // Setup the DFF.. this macro is handy to prevent latches
1457//!#        dff_setup!(self, clock, my_reg);
1458//!#        self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
1459//!#        self.sig_sum.next = self.my_reg.q.val();
1460//!#    }
1461//!# }
1462//!    use rand::{thread_rng, Rng};
1463//!    use std::num::Wrapping;
1464//!    // Build a set of test cases for the circuit.  Use Wrapping to emulate hardware.
1465//!    let test_cases = (0..512)
1466//!        .map(|_| {
1467//!            let a_val = thread_rng().gen::<u8>();
1468//!            let b_val = thread_rng().gen::<u8>();
1469//!            let c_val = (Wrapping(a_val) + Wrapping(b_val)).0;
1470//!            (
1471//!                a_val.to_bits::<8>(),
1472//!                b_val.to_bits::<8>(),
1473//!                c_val.to_bits::<8>(),
1474//!            )
1475//!        })
1476//!        .collect::<Vec<_>>();
1477//!    // The clock speed doesn't really matter here. So 100MHz is fine.
1478//!    let mut sim = simple_sim!(MyAdder, clock, 100_000_000, ep, {
1479//!        let mut x = ep.init()?; // Get the circuit
1480//!        for test_case in &test_cases {
1481//!            // +--  This should look familiar.  Same rules as for HDL kernels
1482//!            // v    Write to .next, read from .val()
1483//!            x.sig_a.next = test_case.0;
1484//!            x.sig_b.next = test_case.1;
1485//!            // Helpful macro to delay the simulate by 1 clock cycle (to allow the output to update)
1486//!            wait_clock_cycle!(ep, clock, x);
1487//!            // You can use any standard Rust stuff inside the testbench.
1488//!            println!(
1489//!                "Test case {:x} + {:x} = {:x} (check {:x})",
1490//!                test_case.0,
1491//!                test_case.1,
1492//!                x.sig_sum.val(),
1493//!                test_case.2
1494//!            );
1495//!            // The `sim_assert_eq` macro stops the simulation gracefully.
1496//!            sim_assert_eq!(ep, x.sig_sum.val(), test_case.2, x);
1497//!        }
1498//!        // When the testbench is complete, call done on the endpoint, and pass the circuit back.
1499//!        ep.done(x)
1500//!    });
1501//!    // Run the simulation - needs a boxed circuit, and a maximum duration.
1502//!    sim.run(MyAdder::default().into(), sim_time::ONE_MILLISECOND)
1503//!        .unwrap();
1504//! ```
1505//!
1506//! The above should write the following to your console (your numbers will be different)
1507//!
1508//!```bash
1509//!Test case 5d + 98 = f5 (check f5)
1510//!Test case 3b + 44 = 7f (check 7f)
1511//!Test case 5d + b0 = 0d (check 0d)
1512//!Test case f8 + 38 = 30 (check 30)
1513//!Test case 73 + b5 = 28 (check 28)
1514//!Test case 1b + e5 = 00 (check 00)
1515//!Test case c1 + 89 = 4a (check 4a)
1516//! etc...
1517//!```
1518//!
1519//! You can also generate a trace of the circuit using the `vcd` (Value Change Dump) format, and
1520//! read the output using `gtkwave` or some other `vcd` viewer.  RustHDL includes a simple
1521//! `vcd` renderer for convenience, but its pretty basic, and mostly for creating documentation
1522//! examples.  It does have the advantage of being callable directly from your testbench in case
1523//! you need some visual verification of your circuit.  
1524//!
1525//! We can make a one line change to our previous example, and generate a `vcd`.
1526//!
1527//! ```rust
1528//!# use rust_hdl::prelude::*;   // <- shorthand to bring in all definitions
1529//!#
1530//!# //        v--- Required by RustHDL
1531//!# #[derive(LogicBlock, Default)]
1532//!# struct MyAdder {
1533//!#     pub sig_a: Signal<In, Bits<8>>,
1534//!#     pub sig_b: Signal<In, Bits<8>>,
1535//!#     pub sig_sum: Signal<Out, Bits<8>>,
1536//!#     pub clock: Signal<In, Clock>,
1537//!#     my_reg: DFF<Bits<8>>,
1538//!# }
1539//!#
1540//!# impl Logic for MyAdder {
1541//!#   #[hdl_gen]  // <--- don't forget this
1542//!#   fn update(&mut self) {
1543//!#        // Setup the DFF.. this macro is handy to prevent latches
1544//!#        dff_setup!(self, clock, my_reg);
1545//!#        self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
1546//!#        self.sig_sum.next = self.my_reg.q.val();
1547//!#    }
1548//!# }
1549//!#    use rand::{thread_rng, Rng};
1550//!#    use std::num::Wrapping;
1551//!#    // Build a set of test cases for the circuit.  Use Wrapping to emulate hardware.
1552//!#    let test_cases = (0..512)
1553//!#        .map(|_| {
1554//!#            let a_val = thread_rng().gen::<u8>();
1555//!#            let b_val = thread_rng().gen::<u8>();
1556//!#            let c_val = (Wrapping(a_val) + Wrapping(b_val)).0;
1557//!#            (
1558//!#                a_val.to_bits::<8>(),
1559//!#                b_val.to_bits::<8>(),
1560//!#                c_val.to_bits::<8>(),
1561//!#            )
1562//!#        })
1563//!#        .collect::<Vec<_>>();
1564//!#    // The clock speed doesn't really matter here. So 100MHz is fine.
1565//!#    let mut sim = simple_sim!(MyAdder, clock, 100_000_000, ep, {
1566//!#        let mut x = ep.init()?; // Get the circuit
1567//!#        for test_case in &test_cases {
1568//!#            // +--  This should look familiar.  Same rules as for HDL kernels
1569//!#            // v    Write to .next, read from .val()
1570//!#            x.sig_a.next = test_case.0;
1571//!#            x.sig_b.next = test_case.1;
1572//!#            // Helpful macro to delay the simulate by 1 clock cycle (to allow the output to update)
1573//!#            wait_clock_cycle!(ep, clock, x);
1574//!#            // You can use any standard Rust stuff inside the testbench.
1575//!#            println!(
1576//!#                "Test case {:x} + {:x} = {:x} (check {:x})",
1577//!#                test_case.0,
1578//!#                test_case.1,
1579//!#                x.sig_sum.val(),
1580//!#                test_case.2
1581//!#            );
1582//!#            // The `sim_assert_eq` macro stops the simulation gracefully.
1583//!#            sim_assert_eq!(ep, x.sig_sum.val(), test_case.2, x);
1584//!#        }
1585//!#        // When the testbench is complete, call done on the endpoint, and pass the circuit back.
1586//!#        ep.done(x)
1587//!#    });
1588//!    // Run the simulation - needs a boxed circuit, and a maximum duration.
1589//!    sim.run_to_file(
1590//!        MyAdder::default().into(),
1591//!        sim_time::ONE_MILLISECOND,
1592//!        &vcd_path!("my_adder.vcd"),
1593//!    )
1594//!    .unwrap();
1595//!    vcd_to_svg(
1596//!        &vcd_path!("my_adder.vcd"),
1597//!        "images/my_adder.svg",
1598//!        &[
1599//!            "uut.clock",
1600//!            "uut.sig_a",
1601//!            "uut.sig_b",
1602//!            "uut.my_reg.d",
1603//!            "uut.my_reg.q",
1604//!            "uut.sig_sum",
1605//!        ],
1606//!        0,
1607//!        100 * sim_time::ONE_NANOSECOND,
1608//!    )
1609//!    .unwrap()
1610//! ```
1611//! The result of that simulation is here.
1612//! ![my_adder_sim](https://github.com/samitbasu/rust-hdl/raw/main/rust-hdl/images/my_adder.svg)
1613//! Note that the digital flip flop copies it's input from `d` to `q` on the leading edge of the clock.
1614//!
1615//! ## Generating Verilog
1616//!
1617//! At some point, you will want to generate Verilog so you can send your design to other
1618//! tools.  This is pretty simple.  You call [generate_verilog] and pass it a reference
1619//! to the circuit in question.  The [generate_verilog] function will check your circuit,
1620//! and then return a string that contains the Verilog equivalent.  It's pretty simple.
1621//!
1622//! Here is an example.  We will reuse the `MyAdder` circuit from the testbench section,
1623//! but this time, generate the Verilog for the circuit instead of simulating it.
1624//!
1625//! ```rust
1626//! use rust_hdl::prelude::*;   // <- shorthand to bring in all definitions
1627//!
1628//! //        v--- Required by RustHDL
1629//! #[derive(LogicBlock, Default)]
1630//! struct MyAdder {
1631//!     pub sig_a: Signal<In, Bits<8>>,
1632//!     pub sig_b: Signal<In, Bits<8>>,
1633//!     pub sig_sum: Signal<Out, Bits<8>>,
1634//!     pub clock: Signal<In, Clock>,
1635//!     my_reg: DFF<Bits<8>>,
1636//! }
1637//!
1638//! impl Logic for MyAdder {
1639//!   #[hdl_gen]  // <--- don't forget this
1640//!   fn update(&mut self) {
1641//!        // Setup the DFF.. this macro is handy to prevent latches
1642//!        dff_setup!(self, clock, my_reg);
1643//!        self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
1644//!        self.sig_sum.next = self.my_reg.q.val();
1645//!    }
1646//! }
1647//!
1648//! let mut uut = MyAdder::default();
1649//! uut.connect_all();
1650//! println!("{}", generate_verilog(&uut));
1651//! ```
1652//!
1653//! You should get the following generated code in your console:
1654//! ```verilog
1655//! module top(sig_a,sig_b,sig_sum,clock);
1656//!
1657//!     // Module arguments
1658//!     input wire  [7:0] sig_a;
1659//!     input wire  [7:0] sig_b;
1660//!     output reg  [7:0] sig_sum;
1661//!     input wire  clock;
1662//!
1663//!     // Stub signals
1664//!     reg  [7:0] my_reg$d;
1665//!     wire  [7:0] my_reg$q;
1666//!     reg  my_reg$clock;
1667//!
1668//!     // Sub module instances
1669//!     top$my_reg my_reg(
1670//!         .d(my_reg$d),
1671//!         .q(my_reg$q),
1672//!         .clock(my_reg$clock)
1673//!     );
1674//!
1675//!     // Update code
1676//!     always @(*) begin
1677//!         my_reg$clock = clock;
1678//!         my_reg$d = my_reg$q;
1679//!         my_reg$d = sig_a + sig_b;
1680//!         sig_sum = my_reg$q;
1681//!     end
1682//!
1683//! endmodule // top
1684//!
1685//!
1686//! module top$my_reg(d,q,clock);
1687//!
1688//!     // Module arguments
1689//!     input wire  [7:0] d;
1690//!     output reg  [7:0] q;
1691//!     input wire  clock;
1692//!
1693//!     // Update code (custom)
1694//!     initial begin
1695//!        q = 8'h0;
1696//!     end
1697//!
1698//!     always @(posedge clock) begin
1699//!        q <= d;
1700//!     end
1701//!
1702//! endmodule // top$my_reg
1703//! ```
1704//!
1705//! A few things about the Verilog generated.
1706//!   - It is hierarchical (scoped) by design.  The scopes mimic the scopes inside the RustHDL circuit.
1707//!  That makes it easy to map the Verilog back to the RustHDL code if needed when debugging.
1708//!   - The code is readable and formatted.
1709//!   - The names correspond to the names in RustHDL, which makes it easy to see the details of the logic.
1710//!   - RustHDL (at least for this trivial example) is a pretty thin wrapper around Verilog.  That's
1711//! good for compatibility with tooling.
1712//!
1713//! While most FPGAs will require you to use a proprietary and closed source toolchain to synthesize
1714//! your design, you can use the open source [Yosys] compiler (if you have it installed) to
1715//! check your designs.  For that, you can use the [yosys_validate] function, which runs the Verilog
1716//! through some checks and reports on potential errors.  At the moment, [Yosys] is far more
1717//! thorough in it's checking than RustHDL, so I highly recommend you install it and use the
1718//! [yosys_validate] function on your generated Verilog.
1719//!
1720//! ## Struct valued signals
1721//!
1722//! We have seen how Enums and Interfaces can help make your code more compact and readable.  There
1723//! is another abstraction you can use to simplify your code.  Interfaces allow you to group together
1724//! signals that are logically related into a named bundle (like a bus).  You can also group
1725//! together `bits` into a logically related bundle that can be treated as a single entity.  
1726//! While this is supported in RustHDL, it's not frequently that useful.  Nonetheless.
1727//!
1728//! Suppose you have a set of signals to your circuit that all travel in the same direction,
1729//! but are different widths.  Any maybe some of the elements are enums.  Something like this
1730//!
1731//! ```rust
1732//!# use rust_hdl::prelude::*;
1733//! struct Foo {
1734//!    pub in_red: Signal<In, Bits<5>>,
1735//!    pub in_green: Signal<In, Bits<8>>,
1736//!    pub in_blue: Signal<In, Bits<8>>,
1737//!    pub in_alpha: Signal<In, Bits<6>>,
1738//! }
1739//! ```
1740//!
1741//! Instead, we can define a struct and annotate it with [LogicStruct], which makes it into a
1742//! type that can be used for a signal.
1743//! ```rust
1744//!# use rust_hdl::prelude::*;
1745//!    #[derive(Default, PartialEq, LogicStruct, Copy, Clone, Debug)]
1746//!    struct Color {
1747//!        pub red: Bits<5>,
1748//!        pub green: Bits<8>,
1749//!        pub blue: Bits<8>,
1750//!        pub alpha: Bits<6>,
1751//!    }
1752//!
1753//!    struct Foo {
1754//!        pub in_color: Signal<In, Color>,
1755//!        pub local_color: Signal<Local, Color>,
1756//!        pub out_color: Signal<Out, Color>,
1757//!    }
1758//!
1759//!    impl Logic for Foo {
1760//!        #[hdl_gen]
1761//!        fn update(&mut self) {
1762//!            self.local_color.next = self.in_color.val(); // Copy the struct as a single atom
1763//!                                     // v-- Extract a single field using standard `.field` notation
1764//!            if self.local_color.val().alpha.get_bit(4) {
1765//!                self.local_color.next.red = 16.into(); // Assign to a single field of the struct
1766//!            }
1767//!            self.out_color.next = self.local_color.val();
1768//!        }
1769//!    }
1770//! ```
1771//!
1772//! From within the HDL kernel, you can access the fields of the struct as you normally would.  You can
1773//! also assign entire structs to one another, as well as individual fields of a struct.  The generated
1774//! Verilog is messy, and I don't use struct valued signals much.  But if you need to use them they are
1775//! there.
1776//!
1777//! ## Loops and Arrays
1778//!
1779//! A frequently useful feature of hardware is to be able to handle a variable number of
1780//! inputs or outputs based on some parameter.  Examples might include:
1781//!  - A processing stage with a variable number of passes
1782//!  - A mux with a variable number of inputs
1783//!  - A bank of identical state machines, where the number of banks is variable
1784//!
1785//! In all of these cases, the tool to reach for is an array in RustHDL.  Including an array
1786//! of subcircuits is pretty simple.  You simply use a static sized array (via a `const generic`
1787//! parameter) or a `vec`.  Here is an example of a circuit that contains a configurable number
1788//! of subcircuits, each of which is an instance of the `Pulser` circuit (a standard RustHDL
1789//! widget)
1790//! ```rust
1791//! # use rust_hdl::prelude::*;
1792//!
1793//! struct PulserSet<const N: usize> {
1794//!     pub outs: Signal<Out, Bits<N>>,
1795//!     pub clock: Signal<In, Clock>,
1796//!     pulsers: [Pulser; N]
1797//! }
1798//! ```
1799//!
1800//! In this case, as long as the members of the array implement `Block` (i.e., are circuits),
1801//! everything will work as expected, including simulation and synthesis.  
1802//!
1803//! Frequently, though, having an array of subcircuits means you need a way to loop over them
1804//! in order to do something useful with their inputs or outputs.  Loops are were software-centric
1805//! thinking can get you into trouble very quickly.  In hardware, it's best to think of loops
1806//! in terms of unrolling.  A `for` loop in RustHDL does not actually loop over anything in
1807//! the hardware.  Rather it is a way of repeating a block of code multiple times with a varying
1808//! parameter.
1809//!
1810//! So the `impl Logic` HDL kernel of the [PulserSet] example above might look something like this:
1811//! ```
1812//! # use rust_hdl::prelude::*;
1813//! # struct PulserSet<const N: usize> {
1814//! #  pub outs: Signal<Out, Bits<N>>,
1815//! #  pub clock: Signal<In, Clock>,
1816//! #  pulsers: [Pulser; N]    
1817//! # }
1818//! impl<const N: usize> Logic for PulserSet<N> {
1819//!     #[hdl_gen]
1820//!     fn update(&mut self) {
1821//!         // Connect all the clocks & enable them all
1822//!         for i in 0..N {
1823//!            self.pulsers[i].clock.next = self.clock.val();
1824//!            self.pulsers[i].enable.next = true.into();
1825//!         }
1826//!         // Connect the outputs...
1827//!         self.outs.next = 0.into();
1828//!         for i in 0..N {
1829//!            self.outs.next = self.outs.val().replace_bit(i, self.pulsers[i].pulse.val());
1830//!         }
1831//!     }
1832//! }
1833//! ```
1834//!
1835//! Note that we are both reading and writing from `self.outs` in the same kernel, but we write
1836//! first, which makes it OK.  Reading first would make this latching behavior, and RustHDL (or
1837//! `yosys`) would throw a fit.
1838//!
1839//! You can do some basic manipulations with the index (like using `3*i+4`, for example), but
1840//! don't get carried away.  Those expressions are evaluated by the HDL kernel generator and
1841//! it has a limited vocab.
1842//!
1843//! ## High Level Synthesis
1844//!
1845//! RustHDL supports it's own version of High Level Synthesis (HLS).  Normally, this is some kind
1846//! of strange drag-and-drop based entry or visual programming paradigm.  Worse, still, it could
1847//! be some kind of macro meta-language that you build complex designs out of using a graphical
1848//! editor.  
1849//!
1850//! But that is not the case here!  RustHDL's HLS approach is much simpler.  Essentially,
1851//! even though [Interfaces] are so great, you may not want to use them.  So the core widgets,
1852//! like the [AsynchronousFIFO] do not use Interfaces.  That leads to some pretty gnarly
1853//! circuit definitions.  Here is the [AsynchronousFIFO] for example:
1854//! ```rust
1855//! # use rust_hdl::prelude::*;
1856//! pub struct AsynchronousFIFO<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> {
1857//!     // Read interface
1858//!     pub read: Signal<In, Bit>,
1859//!     pub data_out: Signal<Out, D>,
1860//!     pub empty: Signal<Out, Bit>,
1861//!     pub almost_empty: Signal<Out, Bit>,
1862//!     pub underflow: Signal<Out, Bit>,
1863//!     pub read_clock: Signal<In, Clock>,
1864//!     pub read_fill: Signal<Out, Bits<NP1>>,
1865//!     // Write interface
1866//!     pub write: Signal<In, Bit>,
1867//!     pub data_in: Signal<In, D>,
1868//!     pub full: Signal<Out, Bit>,
1869//!     pub almost_full: Signal<Out, Bit>,
1870//!     pub overflow: Signal<Out, Bit>,
1871//!     pub write_clock: Signal<In, Clock>,
1872//!     pub write_fill: Signal<Out, Bits<NP1>>,
1873//!     // Internals ommitted...
1874//! }
1875//! ```
1876//! Using an [AsynchronousFIFO] requires up to 14 separate signals!  With mixed directions and types!
1877//! Fortunately, there is an HLS wrapper type you can use instead.  It's _much_ simpler
1878//! ```rust
1879//! # use rust_hdl::prelude::*;
1880//! pub struct AsyncFIFO<T: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> {
1881//!     pub bus_write: FIFOWriteResponder<T>,
1882//!     pub write_clock: Signal<In, Clock>,
1883//!     pub bus_read: FIFOReadResponder<T>,
1884//!     pub read_clock: Signal<In, Clock>,
1885//!     fifo: AsynchronousFIFO<T, N, NP1, BLOCK_SIZE>,
1886//! }
1887//!```
1888//!
1889//! In this case, it has only 4 signals, and using it is also much easier.  You can use the
1890//! [FIFOWriteResponder] and [FIFOWriteController] busses to send and receive data from the
1891//! asynchronous fifo.  Even better is the fact that this HLS construct is just a thin wrapper
1892//! around the [AsynchronousFIFO], so when you synthesize it, or plot signals, there is nothing
1893//! extra under the hood.
1894//!
1895//! The HLS library also includes a sort of System-on-chip model in case you want to use it.
1896//! It allows you to connect a set of widgets to a single controller, and route data to them
1897//! over a fixed bus using a very simple protocol.  It won't replace AXI or WishBone, but it
1898//! can be used to build some pretty complicated designs and remain readable.  The test cases
1899//! are a good place to look for some runnable examples of the different SoC widgets.
1900//!
1901//! ## Wrapping IP Cores
1902//!
1903//! Occasionally in RustHDL, you will need to wrap an external IP core or logic primitive supported
1904//! by your hardware, but that is not supported directly in RustHDL.  There best method for wrapping
1905//! Verilog code is to use the [Wrapper](core::ast::Wrapper) struct and provide your own implementation
1906//! of the `hdl` method for your logic.
1907//!
1908//! Here is a minimal example of a clock buffer primitive (that takes a differential clock input
1909//! and provides a single ended clock output).  The Verilog module declaration for the clock buffer is
1910//! simply:
1911//! ```verilog
1912//! module IBUFDS(I, B, O);
1913//!    input I;
1914//!    input B;
1915//!    output O;
1916//! endmodule
1917//! ```
1918//!
1919//! Since the implementation of this device is built into the FPGA (it is a hardware primitive),
1920//! the module definition is enough for the toolchain to construct the device.  Here is a
1921//! complete example of a wrapped version of this for use in RustHDL.
1922//!
1923//!```rust
1924//! # use rust_hdl::prelude::*;
1925//!
1926//! #[derive(LogicBlock, Default)]
1927//! pub struct ClockDriver {
1928//!   pub clock_p: Signal<In, Clock>,
1929//!   pub clock_n: Signal<In, Clock>,
1930//!   pub sys_clock: Signal<Out, Clock>,
1931//! }
1932//!
1933//! impl Logic for ClockDriver {
1934//!     // Our simulation simply forwards the positive clock to the system clock
1935//!     fn update(&mut self) {
1936//!         self.sys_clock.next = self.clock_p.val();
1937//!     }
1938//!     // RustHDL cannot determine what signals are driven based on the declaration
1939//!     // alone.  This method identifies `sys_clock` as being driven by the internal
1940//!     // logic of the device.
1941//!     fn connect(&mut self) {
1942//!         self.sys_clock.connect();
1943//!     }
1944//!     // Normally the `hdl` method is generated by the `derive` macro.  But in this
1945//!     // case we implement it ourselves to wrap the Verilog code.
1946//!      fn hdl(&self) -> Verilog {
1947//!         Verilog::Wrapper(Wrapper {
1948//!           code: r#"
1949//!     // This is basically arbitrary Verilog code that lives inside
1950//!     // a scoped module generated by RustHDL.  Whatever IP cores you
1951//!     // use here must have accompanying core declarations in the
1952//!     // cores string, or they will fail verification.
1953//!     //
1954//!     // In this simple case, we remap the names here
1955//!     IBUFDS ibufds_inst(.I(clock_p), .B(clock_n), .O(sys_clock));
1956//!
1957//! "#.into(),
1958//!     // Some synthesis tools (like [Yosys] need a blackbox declaration so they
1959//!     // can process the Verilog if they do not have primitives in their
1960//!     // libraries for the device.  Other toolchains will strip these out.
1961//!           cores: r#"
1962//! (* blackbox *)
1963//! module IBUFDS(I, B, O);
1964//!   input I;
1965//!   input B;
1966//!   output O;
1967//! endmodule"#.into(),
1968//!         })
1969//!      }
1970//! }
1971//! ```
1972//!
1973
1974#![warn(missing_docs)]
1975
1976///! Tools for documenting RustHDL designs, including the generation of SVGs from simulation waveforms.
1977pub mod docs;
1978///! A series of High Level Synthesis blocks used to build System-on-Chip designs quickly.
1979pub use rust_hdl_hls as hls;
1980///! Prelude module defines common symbols to make importing RustHDL easier.
1981pub mod prelude;
1982///! The core RustHDL module.  Defines variable width bits, signals, logical blocks, etc.
1983pub use rust_hdl_core as core;
1984///! A set of routines for dealing with FPGA specific pieces.  Either tools for synthesis, or
1985/// logic circuits that are specific to an FPGA family.
1986#[cfg(feature = "fpga")]
1987pub use rust_hdl_fpga_support as fpga;
1988///! Support for the OpalKelly devices (including HDL components and the FrontPanel API)
1989#[cfg(feature = "ok")]
1990pub use rust_hdl_ok_core as ok;
1991#[cfg(feature = "ok")]
1992pub use rust_hdl_ok_frontpanel_sys as frontpanel;
1993///! Module that contains all code related to simulating RustHDL designs in Rust (i.e., without
1994///! an external Verilog simulator).
1995pub use rust_hdl_sim as sim;
1996///! A set of core widgets useful for FPGA based designs, all written in RustHDL.  This includes
1997///! elements such as Digital Flip Flops, Block RAMs, ROMs, FIFOs, SDRAM controllers, SPI controllers
1998///! I2C controllers, FIR filters, etc.
1999pub use rust_hdl_widgets as widgets;
2000
2001#[test]
2002fn doc_sim() {
2003    use crate::prelude::*; // <- shorthand to bring in all definitions
2004    use rand::{thread_rng, Rng};
2005    use std::num::Wrapping;
2006
2007    //        v--- Required by RustHDL
2008    #[derive(LogicBlock, Default)]
2009    struct MyAdder {
2010        pub sig_a: Signal<In, Bits<8>>,
2011        pub sig_b: Signal<In, Bits<8>>,
2012        pub sig_sum: Signal<Out, Bits<8>>,
2013        pub clock: Signal<In, Clock>,
2014        my_reg: DFF<Bits<8>>,
2015    }
2016
2017    impl Logic for MyAdder {
2018        #[hdl_gen] // <--- don't forget this
2019        fn update(&mut self) {
2020            // Setup the DFF.. this macro is handy to prevent latches
2021            dff_setup!(self, clock, my_reg);
2022            self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
2023            self.sig_sum.next = self.my_reg.q.val();
2024        }
2025    }
2026
2027    let test_cases = (0..512)
2028        .map(|_| {
2029            let a_val = thread_rng().gen::<u8>();
2030            let b_val = thread_rng().gen::<u8>();
2031            let c_val = (Wrapping(a_val) + Wrapping(b_val)).0;
2032            (
2033                a_val.to_bits::<8>(),
2034                b_val.to_bits::<8>(),
2035                c_val.to_bits::<8>(),
2036            )
2037        })
2038        .collect::<Vec<_>>();
2039    let mut sim = simple_sim!(MyAdder, clock, 100_000_000, ep, {
2040        let mut x = ep.init()?; // Get the circuit
2041        for test_case in &test_cases {
2042            x.sig_a.next = test_case.0;
2043            x.sig_b.next = test_case.1;
2044            wait_clock_cycle!(ep, clock, x);
2045            println!(
2046                "Test case {:x} + {:x} = {:x} (check {:x})",
2047                test_case.0,
2048                test_case.1,
2049                x.sig_sum.val(),
2050                test_case.2
2051            );
2052            sim_assert_eq!(ep, x.sig_sum.val(), test_case.2, x);
2053        }
2054        ep.done(x)
2055    });
2056    /*    sim.run(MyAdder::default().into(), sim_time::ONE_MILLISECOND)
2057    .unwrap();*/
2058    sim.run_to_file(
2059        MyAdder::default().into(),
2060        sim_time::ONE_MILLISECOND,
2061        &vcd_path!("my_adder.vcd"),
2062    )
2063    .unwrap();
2064    vcd_to_svg(
2065        &vcd_path!("my_adder.vcd"),
2066        "/tmp/my_adder.svg",
2067        &[
2068            "uut.clock",
2069            "uut.sig_a",
2070            "uut.sig_b",
2071            "uut.my_reg.d",
2072            "uut.my_reg.q",
2073            "uut.sig_sum",
2074        ],
2075        0,
2076        100 * sim_time::ONE_NANOSECOND,
2077    )
2078    .unwrap()
2079}
2080
2081#[test]
2082fn doc_vlog() {
2083    use crate::prelude::*;
2084
2085    #[derive(Copy, Clone, PartialEq, Debug, LogicState)]
2086    enum State {
2087        Idle,
2088        Sending,
2089        Receiving,
2090        Done,
2091    }
2092
2093    #[derive(LogicBlock, Default)]
2094    struct Foo {
2095        clock: Signal<In, Clock>,
2096        dff: DFF<State>, // <-- This is a 2 bit DFF
2097    }
2098
2099    impl Logic for Foo {
2100        #[hdl_gen]
2101        fn update(&mut self) {
2102            dff_setup!(self, clock, dff);
2103            match self.dff.q.val() {
2104                State::Idle => {
2105                    self.dff.d.next = State::Sending;
2106                }
2107                State::Sending => {
2108                    self.dff.d.next = State::Receiving;
2109                }
2110                State::Receiving => {
2111                    self.dff.d.next = State::Done;
2112                }
2113                State::Done => {
2114                    self.dff.d.next = State::Idle;
2115                }
2116            }
2117        }
2118    }
2119
2120    let mut uut = Foo::default();
2121    uut.connect_all();
2122    let vlog = generate_verilog(&uut);
2123    println!("{}", vlog);
2124}
2125
2126#[test]
2127fn doc_struct_valued() {
2128    use crate::prelude::*;
2129    #[derive(Default, PartialEq, LogicStruct, Copy, Clone, Debug)]
2130    struct Color {
2131        pub red: Bits<5>,
2132        pub green: Bits<8>,
2133        pub blue: Bits<8>,
2134        pub alpha: Bits<6>,
2135    }
2136
2137    struct Foo {
2138        pub in_color: Signal<In, Color>,
2139        pub local_color: Signal<Local, Color>,
2140        pub out_color: Signal<Out, Color>,
2141    }
2142
2143    impl Logic for Foo {
2144        #[hdl_gen]
2145        fn update(&mut self) {
2146            self.local_color.next = self.in_color.val(); // Copy the struct as a single atom
2147                                                         // v-- Extract a single field using standard `.field` notation
2148            if self.local_color.val().alpha.get_bit(4) {
2149                self.local_color.next.red = 16.into(); // Assign to a single field of the struct
2150            }
2151            self.out_color.next = self.local_color.val();
2152        }
2153    }
2154}
2155
2156#[test]
2157fn doc_verilog_demo() {
2158    use crate::prelude::*; // <- shorthand to bring in all definitions
2159
2160    //        v--- Required by RustHDL
2161    #[derive(LogicBlock, Default)]
2162    struct MyAdder {
2163        pub sig_a: Signal<In, Bits<8>>,
2164        pub sig_b: Signal<In, Bits<8>>,
2165        pub sig_sum: Signal<Out, Bits<8>>,
2166        pub clock: Signal<In, Clock>,
2167        my_reg: DFF<Bits<8>>,
2168    }
2169
2170    impl Logic for MyAdder {
2171        #[hdl_gen] // <--- don't forget this
2172        fn update(&mut self) {
2173            // Setup the DFF.. this macro is handy to prevent latches
2174            dff_setup!(self, clock, my_reg);
2175            self.my_reg.d.next = self.sig_a.val() + self.sig_b.val();
2176            self.sig_sum.next = self.my_reg.q.val();
2177        }
2178    }
2179
2180    let mut uut = MyAdder::default();
2181    uut.connect_all();
2182    println!("{}", generate_verilog(&uut));
2183}