use crate::fifo::async_fifo::AsynchronousFIFO;
use crate::fifo::fifo_expander_n::WordOrder;
use crate::fifo::sync_fifo::SynchronousFIFO;
use crate::prelude::{FIFOExpanderN, FIFOReducerN};
use rust_hdl_core::prelude::*;
#[derive(LogicBlock)]
pub struct CrossWidenFIFO<
const DN: usize, const NN: usize, const NNP1: usize, const DW: usize, const WN: usize, const WNP1: usize, > {
pub data_in: Signal<In, Bits<DN>>,
pub write: Signal<In, Bit>,
pub full: Signal<Out, Bit>,
pub write_clock: Signal<In, Clock>,
pub data_out: Signal<Out, Bits<DW>>,
pub read: Signal<In, Bit>,
pub empty: Signal<Out, Bit>,
pub read_clock: Signal<In, Clock>,
pub in_fifo: AsynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
pub out_fifo: SynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
pub xpand: FIFOExpanderN<DN, DW>,
}
impl<
const DN: usize,
const NN: usize,
const NNP1: usize,
const DW: usize,
const WN: usize,
const WNP1: usize,
> CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
{
pub fn new(order: WordOrder) -> Self {
Self {
data_in: Default::default(),
write: Default::default(),
full: Default::default(),
write_clock: Default::default(),
data_out: Default::default(),
read: Default::default(),
empty: Default::default(),
read_clock: Default::default(),
in_fifo: Default::default(),
out_fifo: Default::default(),
xpand: FIFOExpanderN::new(order),
}
}
}
impl<
const DN: usize,
const NN: usize,
const NNP1: usize,
const DW: usize,
const WN: usize,
const WNP1: usize,
> Default for CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
{
fn default() -> Self {
Self::new(WordOrder::MostSignificantFirst)
}
}
impl<
const DN: usize,
const NN: usize,
const NNP1: usize,
const DW: usize,
const WN: usize,
const WNP1: usize,
> Logic for CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
{
#[hdl_gen]
fn update(&mut self) {
self.in_fifo.data_in.next = self.data_in.val();
self.in_fifo.write.next = self.write.val();
self.full.next = self.in_fifo.full.val();
self.in_fifo.write_clock.next = self.write_clock.val();
self.xpand.data_in.next = self.in_fifo.data_out.val();
self.xpand.empty.next = self.in_fifo.empty.val();
self.in_fifo.read.next = self.xpand.read.val();
self.in_fifo.read_clock.next = self.read_clock.val();
clock!(self, read_clock, xpand, out_fifo);
self.data_out.next = self.out_fifo.data_out.val();
self.empty.next = self.out_fifo.empty.val();
self.out_fifo.read.next = self.read.val();
self.out_fifo.data_in.next = self.xpand.data_out.val();
self.xpand.full.next = self.out_fifo.full.val();
self.out_fifo.write.next = self.xpand.write.val();
}
}
#[test]
fn cross_widen_fifo_is_synthesizable() {
let mut dev = CrossWidenFIFO::<16, 8, 9, 128, 5, 6>::new(WordOrder::MostSignificantFirst);
dev.connect_all();
yosys_validate("cross_wide", &generate_verilog(&dev)).unwrap();
}
#[derive(LogicBlock)]
pub struct CrossNarrowFIFO<
const DW: usize,
const WN: usize,
const WNP1: usize,
const DN: usize,
const NN: usize,
const NNP1: usize,
> {
pub data_in: Signal<In, Bits<DW>>,
pub write: Signal<In, Bit>,
pub full: Signal<Out, Bit>,
pub write_clock: Signal<In, Clock>,
pub data_out: Signal<Out, Bits<DN>>,
pub read: Signal<In, Bit>,
pub empty: Signal<Out, Bit>,
pub read_clock: Signal<In, Clock>,
pub in_fifo: AsynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
pub out_fifo: SynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
pub reducer: FIFOReducerN<DW, DN>,
}
impl<
const DW: usize,
const WN: usize,
const WNP1: usize,
const DN: usize,
const NN: usize,
const NNP1: usize,
> CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
{
pub fn new(order: WordOrder) -> Self {
Self {
data_in: Default::default(),
write: Default::default(),
full: Default::default(),
write_clock: Default::default(),
data_out: Default::default(),
read: Default::default(),
empty: Default::default(),
read_clock: Default::default(),
in_fifo: Default::default(),
out_fifo: Default::default(),
reducer: FIFOReducerN::new(order),
}
}
}
impl<
const DW: usize,
const WN: usize,
const WNP1: usize,
const DN: usize,
const NN: usize,
const NNP1: usize,
> Logic for CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
{
#[hdl_gen]
fn update(&mut self) {
self.in_fifo.data_in.next = self.data_in.val();
self.in_fifo.write.next = self.write.val();
self.full.next = self.in_fifo.full.val();
self.in_fifo.write_clock.next = self.write_clock.val();
self.reducer.data_in.next = self.in_fifo.data_out.val();
self.reducer.empty.next = self.in_fifo.empty.val();
self.in_fifo.read.next = self.reducer.read.val();
self.in_fifo.read_clock.next = self.read_clock.val();
clock!(self, read_clock, reducer, out_fifo);
self.data_out.next = self.out_fifo.data_out.val();
self.empty.next = self.out_fifo.empty.val();
self.out_fifo.read.next = self.read.val();
self.out_fifo.data_in.next = self.reducer.data_out.val();
self.reducer.full.next = self.out_fifo.full.val();
self.out_fifo.write.next = self.reducer.write.val();
}
}
impl<
const DW: usize,
const WN: usize,
const WNP1: usize,
const DN: usize,
const NN: usize,
const NNP1: usize,
> Default for CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
{
fn default() -> Self {
Self::new(WordOrder::MostSignificantFirst)
}
}
#[test]
fn cross_narrow_fifo_is_synthesizable() {
let mut dev = CrossNarrowFIFO::<128, 5, 6, 16, 8, 9>::new(WordOrder::MostSignificantFirst);
dev.connect_all();
yosys_validate("cross_narrow", &generate_verilog(&dev)).unwrap();
}
#[macro_export]
macro_rules! declare_expanding_fifo {
($name: ident, $narrow_bits: expr, $narrow_count: expr, $wide_bits: expr, $wide_count: expr) => {
pub type $name = CrossWidenFIFO<
$narrow_bits,
{ clog2($narrow_count) },
{ clog2($narrow_count) + 1 },
$wide_bits,
{ clog2($wide_count) },
{ clog2($wide_count) + 1 },
>;
};
}
#[macro_export]
macro_rules! declare_narrowing_fifo {
($name: ident, $wide_bits: expr, $wide_count: expr, $narrow_bits: expr, $narrow_count: expr) => {
pub type $name = CrossNarrowFIFO<
$wide_bits,
{ clog2($wide_count) },
{ clog2($wide_count) + 1 },
$narrow_bits,
{ clog2($narrow_count) },
{ clog2($narrow_count) + 1 },
>;
};
}