use rand::Rng; use rust_hdl::prelude::*; #[derive(LogicState, Debug, Copy, Clone, PartialEq)] enum FIFOFeederState { Idle, Running, Sleeping, Done, } #[derive(LogicBlock)] pub struct LazyFIFOFeeder { pub clock: Signal, pub bus: FIFOWriteController, pub done: Signal, pub start: Signal, state: DFF, sleep_counter: DFF>, index: DFF>, data_rom: ROM, sleep_rom: ROM, N>, data_len: Constant>, } impl LazyFIFOFeeder { pub fn new(data: &[T], sleeps: &[Bits<32>]) -> LazyFIFOFeeder { assert!(clog2(data.len()) <= N); assert_eq!(data.len(), sleeps.len()); Self { clock: Default::default(), bus: Default::default(), done: Default::default(), start: Default::default(), state: Default::default(), sleep_counter: Default::default(), index: Default::default(), data_rom: data.to_vec().into_iter().into(), sleep_rom: sleeps.to_vec().into_iter().into(), data_len: Constant::new(data.len().to_bits()), } } } impl Logic for LazyFIFOFeeder { #[hdl_gen] fn update(&mut self) { dff_setup!(self, clock, state, sleep_counter, index); // Wire the FIFO bus to our data array self.bus.data.next = self.data_rom.data.val(); self.bus.write.next = false; // Connect the ROMS self.sleep_rom.address.next = self.index.q.val(); self.data_rom.address.next = self.index.q.val(); self.done.next = false; match self.state.q.val() { FIFOFeederState::Idle => { if self.start.val() { self.state.d.next = FIFOFeederState::Running; } } FIFOFeederState::Running => { if !self.bus.full.val() { self.bus.write.next = true; if self.index.q.val() == (self.data_len.val() - 1) { self.state.d.next = FIFOFeederState::Done; } else if self.sleep_rom.data.val().any() { self.state.d.next = FIFOFeederState::Sleeping; self.sleep_counter.d.next = self.sleep_rom.data.val(); } else { self.index.d.next = self.index.q.val() + 1; } } } FIFOFeederState::Sleeping => { if self.sleep_counter.q.val() == 0 { self.state.d.next = FIFOFeederState::Running; self.index.d.next = self.index.q.val() + 1; } else { self.sleep_counter.d.next = self.sleep_counter.q.val() - 1; } } FIFOFeederState::Done => { self.done.next = true; } _ => { self.state.d.next = FIFOFeederState::Idle; } } } } #[derive(LogicBlock)] pub struct LazyFIFOReader { pub clock: Signal, pub bus: FIFOReadController, pub done: Signal, pub start: Signal, pub error: Signal, mismatch: DFF, state: DFF, sleep_counter: DFF>, index: DFF>, data_rom: ROM, sleep_rom: ROM, N>, data_len: Constant>, } impl LazyFIFOReader { pub fn new(data: &[T], sleeps: &[Bits<32>]) -> LazyFIFOReader { assert!(clog2(data.len()) <= N); assert_eq!(data.len(), sleeps.len()); Self { clock: Default::default(), bus: Default::default(), done: Default::default(), start: Default::default(), error: Default::default(), mismatch: Default::default(), state: Default::default(), sleep_counter: Default::default(), index: Default::default(), data_rom: data.to_vec().into_iter().into(), sleep_rom: sleeps.to_vec().into_iter().into(), data_len: Constant::new(data.len().to_bits()), } } } impl Logic for LazyFIFOReader { #[hdl_gen] fn update(&mut self) { dff_setup!(self, clock, mismatch, state, sleep_counter, index); self.bus.read.next = false; self.done.next = false; // Connect the ROMS self.sleep_rom.address.next = self.index.q.val(); self.data_rom.address.next = self.index.q.val(); self.error.next = self.mismatch.q.val(); match self.state.q.val() { FIFOFeederState::Idle => { if self.start.val() { self.state.d.next = FIFOFeederState::Running; } } FIFOFeederState::Running => { if !self.bus.empty.val() { if self.bus.data.val() != self.data_rom.data.val() { self.mismatch.d.next = true; } self.bus.read.next = true; if self.index.q.val() == (self.data_len.val() - 1) { self.state.d.next = FIFOFeederState::Done; } else if self.sleep_rom.data.val().any() { self.state.d.next = FIFOFeederState::Sleeping; self.sleep_counter.d.next = self.sleep_rom.data.val(); } else { self.index.d.next = self.index.q.val() + 1; } } } FIFOFeederState::Sleeping => { if self.sleep_counter.q.val() == 0 { self.state.d.next = FIFOFeederState::Running; self.index.d.next = self.index.q.val() + 1; } else { self.sleep_counter.d.next = self.sleep_counter.q.val() - 1; } } FIFOFeederState::Done => { self.done.next = true; } _ => { self.state.d.next = FIFOFeederState::Idle; } } } } pub fn bursty_rand() -> Bits<32> { if rand::thread_rng().gen::() < 0.9 { Bits::from(0) } else { Bits::from((rand::thread_rng().gen::() * 40.0) as LiteralType) } } pub fn bursty_vec(len: usize) -> Vec> { (0..len).map(|_| bursty_rand()).collect() }