6个版本 (破坏性更新)
0.4.0 | 2024年2月22日 |
---|---|
0.3.0 | 2024年1月23日 |
0.2.0 | 2023年12月12日 |
0.1.1 | 2023年12月5日 |
0.0.0 | 2022年7月7日 |
#177 in 算法
575KB
12K SLoC
星光
这提供了一个HDL(硬件设计语言)、组合和时序逻辑模拟器和优化器,以及通用路由器,用于FPGA等。其特别之处在于,它是用普通的Rust代码编写的,具有Rust提供的所有功能。
此crate的大部分MVP功能已就绪,但路由器(Router
)仍处于WIP状态,并且有很多todo!()
;
请参阅awint
/awint_dag
的文档,它是此的后端。 awint
是基础库,操作据此建模。 awint_dag
允许记录任意位宽整数操作的DAG。 starlight
将高级操作降低到简单的查找表DAG,并添加了如Loop
之类的时序结构。它可以优化、评估和反推DAG
中的值,以满足各种目的。
此crate有多个功能可启用awint
功能。 u32_ptrs
功能显著减少了算法的内存消耗,但限制了可能的内部引用数约为40亿,这可能导致最大的电路无法适应。
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);
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);
依赖关系
~2.5–3.5MB
~65K SLoC