1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// NOTE: remember to update the README when updating this
//! This provides an HDL (Hardware Design Language), combinational and temporal
//! logic simulator and optimizer, and general purpose router for FPGAs and
//! more. The HDL is special in that it is written in ordinary Rust code with
//! all the features that Rust provides.
//!
//! Most of the MVP features of this crate are ready, except for the `Router`
//! which is still a WIP and has a lot of `todo!()`;
//!
//! See the documentation of `awint`/`awint_dag` which is used as the backend
//! for this. `awint` is the base library that operations are modeled off of.
//! `awint_dag` allows for recording a DAG of arbitrary bitwidth integer
//! operations. `starlight` lowers high level operations down into a DAG of
//! simple lookup tables, and also adds on temporal structs like `Loop`s. It can
//! optimize, evaluate, and retroactively change values in the `DAG` for various
//! purposes.
//!
//! There are several features on this crate that enable `awint` features. The
//! `u32_ptrs` feature reduces the memory consumption of the algorithms
//! significantly, but limits the number of possible internal references to
//! about 4 billion, which the largest circuits might not fit in.
//!
//! ```rust
//! use std::num::NonZeroUsize;
//! use starlight::{awi, dag, Epoch, EvalAwi, LazyAwi};
//!
//! // in the scope where this is glob imported, all arbitrary width types, some primitives, and
//! // the mechanisms in the macros will use mimicking types and be lazily evaluated in general.
//! use dag::*;
//!
//! // This is just some arbitrary example I coded up, note that you can use
//! // almost all of Rust's features that you can use on the normal types
//! struct StateMachine {
//! data: inlawi_ty!(16),
//! counter: Awi,
//! }
//!
//! impl StateMachine {
//! pub fn new(w: NonZeroUsize) -> Self {
//! Self {
//! data: inlawi!(0u16),
//! counter: Awi::zero(w),
//! }
//! }
//!
//! pub fn update(&mut self, input: &Bits) -> Option<()> {
//! self.counter.inc_(true);
//!
//! let mut s0 = inlawi!(0u4);
//! let mut s1 = inlawi!(0u4);
//! let mut s2 = inlawi!(0u4);
//! let mut s3 = inlawi!(0u4);
//! cc!(self.data; s3, s2, s1, s0)?;
//! s2.xor_(&s0)?;
//! s3.xor_(&s1)?;
//! s1.xor_(&s2)?;
//! s0.xor_(&s3)?;
//! s3.rotl_(1)?;
//! s2.mux_(&input, input.get(0)?)?;
//! cc!(s3, s2, s1, s0; self.data)?;
//! Some(())
//! }
//! }
//!
//! // First, create an epoch, this will live until this struct is dropped. The
//! // epoch needs to live until all mimicking operations are done and states are
//! // lowered. Manually drop it with the `drop` function to avoid mistakes.
//! let epoch = Epoch::new();
//!
//! let mut m = StateMachine::new(bw(4));
//!
//! // this is initially an opaque value that cannot be eagerly evaluated
//! let input = LazyAwi::opaque(bw(4));
//!
//! // if we later retroactively assign this to an unequal value, the
//! // `assert_assertions_strict` call will error and show the location of the
//! // assertion that errored
//! mimick::assert_eq!(Awi::from(&input), awi!(0101));
//!
//! // step the state machine forward
//! m.update(&input).unwrap();
//! m.update(&awi!(0110)).unwrap();
//! m.update(&awi!(0110)).unwrap();
//!
//! // use `EvalAwi`s to evaluate the resulting values
//! let output_counter = EvalAwi::from(m.counter);
//! let output_data = EvalAwi::from(m.data);
//!
//! {
//! // switch back to normal structs
//! use awi::*;
//!
//! // discard all unused mimicking states so the render is cleaner
//! epoch.prune_unused_states().unwrap();
//!
//! // See the mimicking state DAG before it is lowered
//! epoch
//! .render_to_svgs_in_dir(std::path::PathBuf::from("./".to_owned()))
//! .unwrap();
//!
//! // lower into purely static bit movements and lookup tables and optimize
//! epoch.optimize().unwrap();
//!
//! // Now the combinational logic is described in a DAG of lookup tables that we
//! // could use for various purposes
//! epoch.ensemble(|ensemble| {
//! for state in ensemble.stator.states.vals() {
//! assert!(state.lowered_to_lnodes);
//! }
//! });
//!
//! // "retroactively" assign the input with a non-opaque value
//! input.retro_(&awi!(0101)).unwrap();
//! // check assertions (all `dag::assert*` functions and dynamic `unwrap`s done
//! // during the current `Epoch`)
//! epoch.assert_assertions(true).unwrap();
//! // evaluate the outputs
//! assert_eq!(output_counter.eval().unwrap(), awi!(0011));
//! assert_eq!(output_data.eval().unwrap(), awi!(0xa505_u16));
//!
//! // reassign and reevaluate
//! input.retro_(&awi!(1011)).unwrap();
//! assert!(epoch.assert_assertions(true).is_err());
//! assert_eq!(output_data.eval().unwrap(), awi!(0x7b0b_u16));
//! }
//! drop(epoch);
//! ```
//!
//! ```rust
//! use starlight::{dag, awi, Epoch, EvalAwi};
//!
//! use dag::*;
//!
//! let epoch = Epoch::new();
//!
//! let mut lhs = inlawi!(zero: ..8);
//! let rhs = inlawi!(umax: ..8);
//! let x = inlawi!(10101010);
//! let y = InlAwi::from_u64(4);
//!
//! let mut output = inlawi!(0xffu8);
//!
//! // error: expected `bool`, found struct `bool`
//! //if lhs.ult(&rhs).unwrap() {
//! // output.xor_(&x).unwrap();
//! //} else {
//! // output.lshr_(y.to_usize()).unwrap();
//! //};
//!
//! // A little more cumbersome, but we get to use all the features of
//! // normal Rust in metaprogramming and don't have to support an entire DSL.
//! // In the future we will have more macros to help with this.
//!
//! let lt = lhs.ult(&rhs).unwrap();
//!
//! let mut tmp0 = output;
//! tmp0.xor_(&x).unwrap();
//! output.mux_(&tmp0, lt).unwrap();
//!
//! let mut tmp1 = output;
//! tmp1.lshr_(y.to_usize()).unwrap();
//! output.mux_(&tmp1, !lt).unwrap();
//!
//! let output_eval = EvalAwi::from(&output);
//!
//! {
//! use awi::*;
//! assert_eq!(output_eval.eval().unwrap(), awi!(01010101));
//! }
//! drop(epoch);
//! ```
/// Data structure internals used by this crate
/// Internal definitions used in lowering
/// WIP routing functionality
/// Miscellanious utilities
pub use ;
pub use triple_arena_render;
pub use ;
pub use ;
pub use Error;
/// Reexports all the regular arbitrary width integer structs, macros, common
/// enums, and most of `core::primitive::*`. This is useful for glob importing
/// everything or for when using the regular items in a context with structs
/// imported from `awint_dag`.
/// Reexports all the mimicking versions of `awi` items
// TODO use modified Lagrangians that appear different to nets with different
// requirements on critical path, plus small differencing values to prevent
// alternating constraint problems