rhdl_bits/lib.rs
1#![warn(missing_docs)]
2//! This crate provides two types that are important for working with hardware
3//! designs.  The [Bits] type is a fixed-size unsigned integer type with a variable
4//! number of bits.  The [SignedBits] type is a fixed-size signed integer type with
5//! a variable number of bits.  Both types are designed to mimic the behavior of
6//! fixed width binary-represented integers as typically are synthesized in hardware
7//! designs.  
8//!
9//! One significant difference between hardware design and software programming is the need
10//! (and indeed ability) to easily manipulate collections of bits that are of various lengths.
11//! While Rust has built in types to represent 8, 16, 32, 64, and 128 bits (at the time of this
12//! writing, anyway), it is difficult to represent a 5 bit type. Or a 256 bit type.  Or indeed
13//! any bit length that is not a power of two or is larger than 128 bits.
14//!
15//! The [Bits] and [SignedBits] types are designed to fill this gap.  They are generic over
16//! the number of bits they represent, and can be used to represent any number of bits from 1
17//! to 128.  The [Bits] type is an unsigned integer type, and the [SignedBits] type is a signed
18//! integer type.  Both types implement the standard Rust traits for integer types, including
19//! [Add](std::ops::Add), [Sub](std::ops::Sub), [BitAnd](std::ops::BitAnd),
20//! [BitOr](std::ops::BitOr), [BitXor](std::ops::BitXor), [Shl](std::ops::Shl),
21//! [Shr](std::ops::Shr), [Not](std::ops::Not), [Eq], [Ord], [PartialEq], [PartialOrd],
22//! [Display](std::fmt::Display), [LowerHex](std::fmt::LowerHex),
23//! [UpperHex](std::fmt::UpperHex), and [Binary](std::fmt::Binary).  
24//! The [SignedBits] type also implements [Neg](std::ops::Neg).  Note that in all cases,
25//! these types implement 2-s complement wrapping arithmetic, just as you would find in
26//! hardware designs.  They do not panic on underflow or overflow, but simply wrap around.
27//! This is the behavior that best mimics real hardware design.  You can, of course,
28//! implement detection for overflow and underflow in your designs, but this is not the
29//! default behavior.
30//!
31//! The two types are also [Copy], which makes them easy to use just like intrinsic integer types.
32//! Some general advice.  Hardware manipulation of bit vectors can seem counterintuitive if you
33//! have not done it before.  The [Bits] and [SignedBits] types are designed to mimic the behavior
34//! of hardware designs, and so they may not behave the way you expect.  If you are not familiar
35//! with 2's complement arithmetic, you should read up on it before using these types.
36//!
37//! # Constructing [Bits]
38//! There are several ways to construct a [Bits] value.  The simplest is to use the
39//! [From] trait, and convert from integer literals.  For example:
40//! ```
41//! use rhdl_bits::Bits;
42//! let bits: Bits<8> = 0b1101_1010.into();
43//! ```
44//! This will work for any integer literal that is in the range of the [Bits] type.
45//! If the literal is outside the range of the [Bits] type, Rust will panic.
46//!
47//! You can also construct a [Bits] value from a [u128] value:
48//! ```
49//! # use rhdl_bits::Bits;
50//! let bits: Bits<8> = 0b1101_1010_u128.into();
51//! ```
52//!
53//! Note that the [Bits] type only supports up to 128 bit values.  Larger bit vectors
54//! can easily be constructed using data structures (arrays, structs, enums, tuples).
55//! But arithmetic on them is not supported by default.  You will need to provide your
56//! own arithmetic implementations for these types.  This is a limitation of the
57//! [Bits] type, but it is a limitation that is not likely to be a problem in practice.
58//! Practical hardware limitations can mean that performing arithmetic on very long
59//! bit vectors is likely to be very slow.
60//!
61//! # Constructing [SignedBits]
62//! The [SignedBits] type can be constructed in the same way as the [Bits] type.  The
63//! only difference is that the [SignedBits] type can be constructed from a [i128] value:
64//! ```
65//! # use rhdl_bits::SignedBits;
66//! let bits: SignedBits<8> = 0b0101_1010_i128.into();
67//! ```
68//!
69//! Likewise, you can construct a [SignedBits] from a signed literal
70//! ```
71//! # use rhdl_bits::SignedBits;
72//! let bits: SignedBits<8> = (-42).into();
73//! ```
74//! *Note the parenthesis!*  Because of the order of operations, the negation has a lower
75//! precedence than the `.into()`.  As a result, if you omit the parenthesis, you will
76//! get a Rust complaint about not being able to decide what type the integer literal must
77//! assume.  This is unfortunate, but unavoidable.
78//!
79//! # Operations
80//! Only a subset of operations are defined for [Bits] and [SignedBits].  These are
81//! the operations that can be synthesized in hardware without surprises (generally
82//! speaking).  In Rust, you can operate between [Bits] types and other [Bits] types
83//! of the _same width_, or you can use integer literals, which will be converted to
84//! [Bits] types of the appropriate width.  For example:
85//! ```
86//! # use rhdl_bits::Bits;
87//! let bits: Bits<8> = 0b1101_1010.into();
88//! let result = bits & 0b1111_0000;
89//! assert_eq!(result, 0b1101_0000);
90//! ```
91//!
92//! Note that in case the `result` is being directly compared to an integer literal.
93//!
94//! You can also operate on [Bits] types of different widths, but you will need to
95//! convert them to the same width first.  For example:
96//! ```
97//! # use rhdl_bits::Bits;
98//! let bits: Bits<8> = 0b1101_1010.into();
99//! let nibble: Bits<4> = 0b1111.into();
100//! let result = bits.slice(4) & nibble;
101//! assert_eq!(result, 0b1101);
102//! ```
103//!
104//! Here the `slice` operator will extract the upper 4 bits of the `bits` value, and
105//! they can then be operated on using the `&` operator.  Note that the `slice` operator
106//! is generic over the width of the slice, so you can extract any number of bits from
107//! the [Bits] value.  If you request more bits than the [Bits] value has, the extra
108//! bits will be initialized to 0.
109//!
110//! ```
111//! # use rhdl_bits::Bits;
112//! let bits: Bits<8> = 0b1101_1010.into();
113//! let word: Bits<16> = bits.slice(0);
114//! assert_eq!(word, 0b0000_0000_1101_1010);
115//! ```
116//!
117//! You can also `slice` [SignedBits] as well.  However, in this case, extra bits
118//! are sign-extended, not zero-extended.  And the end result is a [Bits] type,
119//! not a [SignedBits] type.  For example:
120//!
121//! ```
122//! # use rhdl_bits::{SignedBits, Bits};
123//! let bits: SignedBits<8> = (-42).into();
124//! let word: Bits<16> = bits.slice(0);
125//! assert_eq!(word, 0xFF_D6);
126//! ```
127//!
128//! * Be careful * when using the `slice` operator on [SignedBits] values.  If you
129//! slice a [SignedBits] value to a smaller size, the sign bit will be lost.  For
130//! example:
131//!
132//! ```
133//! # use rhdl_bits::{Bits,SignedBits};
134//! let bits: SignedBits<8> = (-42).into();
135//! let nibble: Bits<4> = bits.slice(0);
136//! assert_eq!(nibble, 6);
137//! ```
138//!
139//! To elaborate on this example, -42 in 8 bits is 1101_0110.  If you slice this
140//! to 4 bits, you get 0110, which is 6.  The sign bit is lost in the slicing.
141//!
142//! ## Bit Widths and Binary Operators
143//!
144//! All of the binary operators follow the same rules:
145//! * Both operands must be of the same width.
146//! * Both operands must be of the same type (e.g., [SignedBits] or [Bits]).
147//! * One of the operands may be a literal, in which case it will be converted to
148//! the appropriate type before the operator is applied.
149//!
150//! These rules are entirely enforced in the Rust type system.  So there is nothing
151//! special about following these rules that you are not already accustomed to.  The
152//! following, for example, will fail to compile:
153//!
154//! ```compile_fail
155//! # use rust_hdl_bits::Bits;
156//! let x: Bits<20> = 0x1234.into();
157//! let y: Bits<21> = 0x5123.into();
158//! let z = x + y; // This will fail to compile.
159//! ```
160//!
161//! ## Addition
162//!
163//! Addition is supported for [Bits] and [SignedBits] types.  You can add two
164//! [Bits] values together, or you can add a [Bits] value to an integer literal.
165//! For example:
166//! ```
167//! # use rhdl_bits::Bits;
168//! let x: Bits<32> = 0xDEAD_BEEE.into();
169//! let y: Bits<32> = x + 1;
170//! assert_eq!(y, 0xDEAD_BEEF);
171//! ```
172//! The order of the arguments does not matter:
173//! ```
174//! # use rhdl_bits::Bits;
175//! let x: Bits<32> = 0xDEAD_BEEE.into();
176//! let y: Bits<32> = 1 + x;
177//! assert_eq!(y, 0xDEAD_BEEF);
178//! ```
179//!
180//! Or using two [Bits] values:
181//! ```
182//! # use rhdl_bits::Bits;
183//! let x: Bits<32> = 0xDEAD_0000.into();
184//! let y: Bits<32> = 0xBEEF.into();
185//! let z: Bits<32> = x + y;
186//! assert_eq!(z, 0xDEAD_BEEF);
187//! ```
188//!
189//! The [AddAssign](std::ops::AddAssign) trait is also implemented for [Bits] and
190//! [SignedBits], so you can use the `+=` operator as well:
191//! ```
192//! # use rhdl_bits::Bits;
193//! let mut x: Bits<32> = 0xDEAD_0000.into();
194//! x += 0xBEEF;
195//! assert_eq!(x, 0xDEAD_BEEF);
196//! ```
197//!
198//! Note that the addition operation os 2's complement wrapping addition.  This is
199//! the behavior that is most useful for hardware designs.  If you want to detect
200//! overflow, you will need to implement that yourself.
201//!
202//! ```
203//! # use rhdl_bits::Bits;
204//! let mut x: Bits<8> = 0b1111_1111.into();
205//! x += 1;
206//! assert_eq!(x, 0);
207//! ```
208//!
209//! In this case, the addition of 1 caused `x` to wrap to all zeros.  This is totally normal,
210//! and what one would expect from hardware addition (without a carry).  If you _need_ the
211//! carry bit, then the solution is to first cast to 1 higher bit, and then add, or alternately,
212//! to compute the carry directly.
213//!
214//! ```
215//! # use rhdl_bits::Bits;
216//! let x: Bits<40> = (0xFF_FFFF_FFFF).into();
217//! let y: Bits<41> = x.slice(0) + 1;
218//! assert_eq!(y, 0x100_0000_0000);
219//! ```
220//!
221//! ## Subtraction
222//! Hardware subtraction is defined using 2s complement arithmetic.  This is pretty
223//! much the universal standard for representing negative numbers and subtraction in
224//! hardware.  The [Sub](std::ops::Sub) trait is implemented for [Bits] and [SignedBits],
225//! and operates much like the [Wrapping](std::num::Wrapping) trait does for the
226//! built in integers in Rust.  Note that overflow and underflow are _not_ detected
227//! in RHDL (nor are they detected in hardware either).  You will need to explicitly
228//! check for overflow or underflow conditions if you want to take action in those
229//! circumstances.
230//!
231//! ```
232//! # use rhdl_bits::Bits;
233//! let x: Bits<8> = 0b0000_0001.into();
234//! let y: Bits<8> = 0b0000_0010.into();
235//! let z: Bits<8> = x - y; // 1 - 2 = -1
236//! assert_eq!(z, 0b1111_1111);
237//! ```
238//!
239//! Note that in this case, we subtracted 2 from 1, and the result was -1.  However,
240//! -1 in 2s complement is `0xFF`, which is stored in `z` as an unsigned value of 255.
241//! This is the same behavior that you experience with `u8` in standard Rust if you
242//! use Wrapping arithmetic:
243//! ```
244//! let x : u8 = 1;
245//! let y : u8 = 2;
246//! let z = u8::wrapping_sub(x, y);
247//! assert_eq!(z, 0b1111_1111);
248//! ```
249//!
250//! I don't want to belabor the point, but wrapping arithmetic and 2s complement
251//! representations can catch people by surprise if they are unfamiliar with
252//! hardware implementations of arithmetic.
253//!
254//! For [SignedBits], the result is the same, but interpreted correctly:
255//! ```
256//! # use rhdl_bits::SignedBits;
257//! let x: SignedBits<8> = 0b0000_0001.into();
258//! let y: SignedBits<8> = 0b0000_0010.into();
259//! let z: SignedBits<8> = x - y; // 1 - 2 = -1
260//! assert_eq!(z, -1);
261//! ```
262//!
263//! The [SubAssign](std::ops::SubAssign) trait is implemented for both [Bits] and [SignedBits],
264//! so you can use the `-=` operator as well:
265//! ```
266//! # use rhdl_bits::Bits;
267//! let mut x: Bits<8> = 0b0000_0001.into();
268//! x -= 1;
269//! assert_eq!(x, 0);
270//! ```
271//!
272//! ## Bitwise Logical Operators
273//!
274//! All four of the standard Rust logical operators are supported for both [Bits] and [SignedBits].
275//! They operate bitwise, and are implemented using the standard Rust traits.  For completeness,
276//! the list of supported bitwise operators is:
277//! - [Or](std::ops::BitOr) and [OrAssign](std::ops::BitOrAssign) for `|` and `|=`
278//! - [And](std::ops::BitAnd) and [AndAssign](std::ops::BitAndAssign) for `&` and `&=`
279//! - [Xor](std::ops::BitXor) and [XorAssign](std::ops::BitXorAssign) for `^` and `^=`
280//! - [Not](std::ops::Not) for `!`
281//! Other, more exotic binary operators (like Xnor or Nand) are not supported.  If you need these,
282//! you will need to implement them in terms of these more basic operators.
283//!
284//! Here is an example of the binary operators in action:
285//! ```
286//! # use rhdl_bits::Bits;
287//! let x: Bits<8> = 0b1101_1010.into();
288//! let y: Bits<8> = 0b1111_0000.into();
289//! let z: Bits<8> = x | y;
290//! assert_eq!(z, 0b1111_1010);
291//! let z: Bits<8> = x & y;
292//! assert_eq!(z, 0b1101_0000);
293//! let z: Bits<8> = x ^ y;
294//! assert_eq!(z, 0b0010_1010);
295//! let z: Bits<8> = !x;
296//! assert_eq!(z, 0b0010_0101);
297//! ```
298//!
299//! Note that you can apply these operators to [SignedBits] as well.  The meaning of the result is up
300//! to you to interpret.  The bitwise operators simply manipulate the bits, and do not care about
301//! the sign of the value.  This is also true for Rust and intrinsic types.
302//!
303//! ```
304//! let x: i8 = -0b0101_1010;
305//! let y: i8 = -0b0111_0000;
306//! let z = x ^ y; // This will be positive
307//! assert_eq!(z, 54);
308//! ```
309//!
310//! ## Shifting
311//!
312//! Shifting is a fairly complex topic, since it involves a few additional details:
313//! - The behavior of [Bits] and [SignedBits] are identical under left shifting.
314//! - The behavior of [Bits] and [SignedBits] are different under right shifting.
315//! - Right shifting a [Bits] will cause `0` to be inserted on the "left" of the value (the MSB).
316//! - Right shifting a [SignedBits] will cause the MSB to be replicated on the "left" of the value.
317//!
318//! The net effect of these differences is that left shifting (to a point) will preserve the
319//! sign of the value, until all the bits are shifted out of the value.  Right shifting will
320//! preserve the sign of the value.  If you want to right shift a [SignedBits] value with 0 insertion
321//! at the MSB, then convert it to a [Bits] first.
322//!
323//! The [Shl](std::ops::Shl) and [ShlAssign](std::ops::ShlAssign) traits are implemented for both
324//! [Bits] and [SignedBits].  The [Shr](std::ops::Shr) and [ShrAssign](std::ops::ShrAssign) traits
325//! are also implemented for both.  Note that unlike the other operators, the shift operators allow
326//! you to use a *different* bit width for the shift amount.  This is because in hardware designs,
327//! the amount of the shift is often controlled dynamically (using circuitry known as a Barrel Shifter).
328//! And the number of bits used to encode the shift will be related to the base-2 log of the number
329//! of bits in the register.  For example, if you have a 32 bit register, you will need 5 bits to
330//! encode the shift amount.  If you have a 64 bit register, you will need 6 bits to encode the
331//! shift amount.  And so on.
332//!
333//! In order to model this, the shift operators are generic over both the number of bits in the value
334//! being shifted, _and_ the number of bits in the value that controls the shift.  For example:
335//! ```
336//! # use rhdl_bits::Bits;
337//! let x: Bits<8> = 0b1101_1010.into();
338//! let y: Bits<3> = 0b101.into();
339//! let z: Bits<8> = x >> y;
340//! assert_eq!(z, 0b0000_0110);
341//! ```
342//!
343//! You can also use an integer literal to control the shift amount
344//! ```
345//! # use rhdl_bits::Bits;
346//! let x: Bits<8> = 0b1101_1010.into();
347//! let z: Bits<8> = x >> 3;
348//! assert_eq!(z, 0b0001_1011);
349//! ```
350//!
351//! There is one critical difference between shift operators on [Bits]/[SignedBits] and the wrapping
352//! Rust operators on intrinsic integers.  Rust will do nothing if you shift by more bits than are
353//! in the value.  For example:
354//! ```
355//! let x: u8 = 0b1101_1010;
356//! let y = u8::wrapping_shl(x,10);
357//! assert_ne!(y, 0b1101_1010); // Note that this is _not_ zero - the result is not even clearly defined.
358//! ```
359//! This is not the case for [Bits] and [SignedBits].  If you shift by more bits than are in the value,
360//! the result will simply be zero (unless you are right shifting a [SignedBits] value, in which case it
361//! will converge to either zero or -1, depending on the sign bit).  This is an odd case to cover, and
362//! it is not clear what the "correct" behavior should be.  But this is the behavior that is implemented
363//! in RHDL.
364//!
365//! ```
366//! # use rhdl_bits::Bits;
367//! let x: Bits<8> = 0b1101_1010.into();
368//! let z: Bits<8> = x >> 10;
369//! assert_eq!(z, 0);
370//! ```
371//!
372//! ## Comparison Operators
373//!
374//! The standard Rust comparison operators are implemented for both [Bits] and [SignedBits].  These
375//! operators are:
376//! - [PartialEq](std::cmp::PartialEq), [Eq](std::cmp::Eq) for `==` and `!=`
377//! - [Ord](std::cmp::Ord) and [PartialOrd](std::cmp::PartialOrd) for `<`, `>`, `<=`, and `>=`
378//!
379//! Note that the comparison operators are implemented using signed arithmetic for [SignedBits], and
380//! unsigned arithmetic for [Bits].  This is the same behavior that you would see in hardware designs.
381//! For example, with [Bits]:
382//! ```
383//! # use rhdl_bits::Bits;
384//! let x: Bits<8> = 0b1111_1111.into();
385//! let y: Bits<8> = 0b0000_0000.into();
386//! assert!(x > y);
387//! ```
388//! On the other hand with [SignedBits]:
389//! ```
390//! # use rhdl_bits::SignedBits;
391//! let x: SignedBits<8> = (-0b0000_0001).into();
392//! let y: SignedBits<8> = 0b0000_0000.into();
393//! assert!(x < y);
394//! assert_eq!(x.as_unsigned(), 0b1111_1111);
395//! ```
396//!
397#[doc(hidden)]
398pub mod add;
399#[doc(hidden)]
400pub mod and;
401#[doc(hidden)]
402pub mod bits;
403#[doc(hidden)]
404pub mod neg;
405#[doc(hidden)]
406pub mod not;
407#[doc(hidden)]
408pub mod or;
409#[doc(hidden)]
410pub mod shl;
411#[doc(hidden)]
412pub mod shr;
413#[doc(hidden)]
414pub mod signed_bits;
415#[doc(hidden)]
416pub mod sub;
417#[doc(hidden)]
418pub mod xor;
419
420pub use bits::bits;
421pub use bits::Bits;
422pub use signed_bits::signed;
423pub use signed_bits::SignedBits;
424
425#[cfg(test)]
426mod test {
427    use super::*;
428    #[test]
429    fn time_adding_120_bit_values() {
430        use std::time::Instant;
431        let mut a = Bits::<120>::default();
432        let mut b = Bits::<120>::default();
433        let mut c = Bits::<120>::default();
434        let start = Instant::now();
435        for _k in 0..100 {
436            for i in 0..120 {
437                for j in 0..120 {
438                    a.set_bit(i, true);
439                    b.set_bit(j, true);
440                    c += a + b;
441                    a.set_bit(i, false);
442                    b.set_bit(j, false);
443                }
444            }
445        }
446        let duration = start.elapsed();
447        println!("Time elapsed in expensive_function() is: {:?}", duration);
448        println!("c = {:b}", c);
449    }
450}