\subsubsection{AlignedFIFOs} \index{AlignedFIFOs@\te{AlignedFIFOs} (package)} \label{sec-AlignedFIFOs} {\bf Package} \begin{verbatim} import AlignedFIFOs :: * ; \end{verbatim} {\bf Description} The AlignedFIFOs package contains a parameterized FIFO module intended for creating synchronizing FIFOs between clock domains with aligned edges for both types of clock domain crossings: \begin{itemize} \item slow-to-fast crossing - every edge in the source domain implies the existence of a simultaneous edge in the destination domain \item fast-to-slow crossing - every edge in the destination domain implies the existence of a simultaneous edge in the source domain \end{itemize} The FIFO is parameterized on the type of store used to hold the FIFO data, which is itself parameterized on the index type, value type, and read latency. Modules to construct stores based on a single register, a vector of registers and a BRAM are provided, and the user can supply their own store implementation as well. The FIFO allows the user to control whether or not outputs are held stable during the full slow clock cycle or allowed to transition mid-cycle. Holding the outputs stable is the safest option but it slightly increases the minimum latency through the FIFO. A primary design goal of this FIFO is to provide an efficient and flexible family of synchronizing FIFOs between aligned clock domains which are written in BSV and are fully compatible with Bluesim. These FIFOs (particularly ones using vectors of registers) may not be the best choice for ASIC synthesis due to the muxing to select the head value in the \te{first} method. {\bf Interfaces and methods} \paragraph{Store Interface} The \te{AlignedFIFO} is parameterized on the type of store used to hold the FIFO data. The three types of stores provided in the \te{AlignedFIFO} package (single-element, vector-of-registers, and BRAM) all return a \te{Store} interface. The \te{Store} interface has a \te{prefetch} method which is used by some modules (the \te{mkBRAMStore} in this package). If a prefetch is used, the \te{read} method returns the value at the previously fetched index; the value of \te{idx} should be ignored. If a prefetch is not used, the \te{read} method index value determines the returned value. % \begin{center} % \begin{tabular}{|p{.4 in}|p{1.5 in}|p{.4in}| p{2 in}|} % \hline % \multicolumn{4}{|c|}{Type parameters used in Interfaces}\\ % \hline % Name&Description&Valid Values&\\ % \hline % \te{i}& data type of index&&\\ % \hline % \te{a} &data type of values in FIFO&&\\ % \hline % \te{n}& Read latency & 0& prefetch is not used \\ % \cline{3-4} % && 1& prefetch is used\\ % \hline % \end{tabular} % \end{center} \begin{center} \begin{tabular}{|p{1.1in}|p{.4in}|p{3.5 in}|} \hline \multicolumn{3}{|c|}{Store Interface Methods}\\ \hline Name & Type & Description\\ \hline \hline \te{write}&Action&Writes the value at index \te{idx}.\\ \hline \te{prefetch}&Action&Initiates a prefetch of the value at index \te{idx}. \\ \hline \te{read}&\te{a}&Returns the value of type \te{a}. If prefetch is not used, returns the value at index \te{idx}. When prefetch is used, returns the value at the previously fetched index; the value of \te{idx} should be ignored.\\ \hline \end{tabular} \end{center} \begin{verbatim} interface Store#(type i, type a, numeric type n); method Action write(i idx, a value); method Action prefetch(i idx); method a read(i idx); endinterface: Store \end{verbatim} \paragraph{AlignedFIFO Interface} The \te{AlignedFIFO} interface provides methods for both source (enqueue) and destination (dequeue) clock domains. \begin{center} \begin{tabular}{|p{1.1in}|p{.4in}|p{3.5 in}|} \hline \multicolumn{3}{|c|}{AlignedFIFO Interface Methods}\\ \hline \hline Name&Type&Description\\ \hline \hline \te{enq}&Action&Adds an entry to the FIFO from the source clock domain.\\ \hline \te{first}&\te{a}&Returns the first entry from the FIFO in the destination clock domain.\\ \hline \te{deq}&Action&Removes the first entry from the FIFO in the destination clock domain.\\ \hline \te{dNotFull}&Bool&Returns \te{True} if the FIFO appears not full from the destination clock domain.\\ \hline \te{dNotEmpty}&Bool&Returns \te{True} if the FIFO appears not empty from the destination clock domain.\\ \hline \te{sNotFull}&Bool&Returns \te{True} if the FIFO appears not full from the source clock domain.\\ \hline \te{sNotEmpty}&Bool&Returns \te{True} if the FIFO appears not empty from the source clock domain.\\ \hline \te{dClear}&Action&Clears the FIFO from the destination side.\\ \hline \te{sClear}&Action&Clears the FIFO from the source side.\\ \hline \end{tabular} \end{center} \begin{verbatim} interface AlignedFIFO#(type a); method Action enq(a x); method a first(); method Action deq(); method Bool dNotFull(); method Bool dNotEmpty(); method Bool sNotFull(); method Bool sNotEmpty(); method Action dClear(); method Action sClear(); endinterface: AlignedFIFO \end{verbatim} {\bf Modules} The \te{AlignedFIFO} module is parameterized on the type of store used to hold the FIFO data. The \te{AlignedFIFOs} package contains modules to construct stores based on a single register (\te{mkRegStore}), a vector of registers (\te{mkRegVectorStore}), and a BRAM (\te{mkBRAMStore}). Users can supply their own store implementation as well. \index{mkRegStore@\te{mkRegStore} (module)} \index[function]{AlignedFIFOs!mkRegStore} The \te{mkRegStore} instantiates a single-element store. The module returns a \te{Store} interface and does not use a prefetch. \begin{center} \begin{tabular}{|p{1.4 in}|p{4.1 in}|} \hline & \\ Module Name & BSV Module Declaration \\ \hline \multicolumn{2}{|l|}{Implementation of a single-element store }\\ \hline \begin{libverbatim}mkRegStore \end{libverbatim} & \begin{libverbatim} module mkRegStore(Clock sClock, Clock dClock, Store#(UInt#(0),a,0) ifc) provisos(Bits#(a,a_sz) ); \end{libverbatim} \\ \hline \end{tabular} \end{center} \index{mkRegVectorStore@\te{mkRegVectorStore} (module)} \index[function]{AlignedFIFOs!mkRegVectorStore} The \te{mkRegVectorStore} module instantiates a vector-of-registers store. The module returns a \te{Store} interface and does not use a prefetch. \begin{center} \begin{tabular}{|p{1.4 in}|p{4.1 in}|} \hline \multicolumn{2}{|l|}{Implementation of a vector-of-registers store}\\ \hline \begin{libverbatim}mkRegVectorStore \end{libverbatim} & \begin{libverbatim} module mkRegVectorStore(Clock sClock, Clock dClock, Store#(UInt#(w),a,0) ifc) provisos( Bits#(a,a_sz) ); \end{libverbatim} \\ \hline \end{tabular} \end{center} \index{mkBRAMStore2W1R@\te{mkBRAMStore2W1R} (module)} \index[function]{AlignedFIFOs!mkBRAMStore2W1R} The \te{mkBRAMStore2W1R} module returns a \te{Store} interface and uses a prefetch. This model assumes the read clock is a 2x divided version of the write clock. \begin{center} \begin{tabular}{|p{1.4 in}|p{4.1 in}|} \hline \multicolumn{2}{|l|}{A BRAM-based store where the read clock is a 2x divided version of the write clock.}\\ \hline \begin{libverbatim}mkBRAMStore2W1R \end{libverbatim} & \begin{libverbatim} module mkBRAMStore2W1R(Clock sClock, Reset sReset, Clock dClock, Reset dReset, Store#(i,a,1) ifc) provisos( Bits#(a,a_sz), Bits#(i,w), Eq#(i) );\end{libverbatim} \\ \hline \end{tabular} \end{center} \index{mkBRAMStore1W2R@\te{mkBRAMStore1W2R} (module)} \index[function]{AlignedFIFOs!mkBRAMStore1W2R} The \te{mkBRAMStore1W2R} module returns a \te{Store} interface and uses a prefetch. This model assumes the write clock is a 2x divided version of the read clock. \begin{center} \begin{tabular}{|p{1.4 in}|p{4.1 in}|} \hline \multicolumn{2}{|l|}{A BRAM-based store where the write clock is a 2x divided version of read clock.}\\ \hline \begin{libverbatim}mkBRAMStore1W2R \end{libverbatim} & \begin{libverbatim} module mkBRAMStore1W2R(Clock sClock, Reset sReset, Clock dClock, Reset dReset, Store#(i,a,1) ifc) provisos( Bits#(a,a_sz), Bits#(i,w), Eq#(i) );\end{libverbatim} \\ \hline \end{tabular} \end{center} \index{mkAlignedFIFO@\te{mkAlignedFIFO} (module)} \index[function]{AlignedFIFOs!mkAlignedFIFO} The \te{mkAlignedFIFO} module makes a synchronizing FIFO for aligned clocks, based on the given backing store (determined by the type of store instantiated). The store is assumed to have $2^{w}$ slots addressed from 0 to $2^{w}-1$. The store will be written in the source clock domain and read in the destination clock domain. The \te{enq} and \te{deq} methods will only be callable when the \te{allow\_enq} and \te{allow\_deq} inputs are high. For a slow-to-fast crossing use: \begin{libverbatim} allow_enq = constant True allow_deq = pre-edge signal \end{libverbatim} For a fast-to-slow crossing, use: \begin{libverbatim} allow_enq = pre-edge signal allow_deq = constant True \end{libverbatim} The pre-edge signal is \te{True} when the slow clock will rise in the next clock cycle. The \te{ClockNextRdy} from the \te{ClockDividerIfc} (Section \ref{sec-clockdivider}) can be used as the pre-edge signal. These settings ensure that the outputs in the slow clock domain are stable for the entire cycle. Setting both inputs to constant True reduces the minimum latency through the FIFO, but allows outputs in the slow domain to transition mid-cycle. This is less safe and can interact badly with the \te{\$displays} in a Verilog simulation. It is not advisable to call both \te{dClear} and \te{sClear} simultaneously. \begin{center} \begin{tabular}{|p{1.4 in}|p{4.1 in}|} \hline \multicolumn{2}{|l|}{Implementation of an aligned FIFO}\\ \hline \begin{libverbatim}mkAlignedFIFO \end{libverbatim} & \begin{libverbatim} (* no_default_clock, no_default_reset *) module mkAlignedFIFO( Clock sClock , Reset sReset , Clock dClock , Reset dReset , Store#(i,a,n) store , Bool allow_enq , Bool allow_deq , AlignedFIFO#(a) ifc ) provisos( Bits#(a,sz_a), Bits#(i,w), Eq#(i), Arith#(i) );\end{libverbatim} \\ \hline \end{tabular} \end{center} % {\bf Verilog Modules} % \te{FIFO} and \te{FIFOF} modules correspond to the following {\V} % modules, which are found in the BSC {\V} library, \te{\$BLUESPECDIR/Verilog/}. % \begin{center} % \begin{tabular} {|p{1.5in}|p{1in}p{1 in}|p{1.8 in}|} % \hline % &&& \\ % BSV Module Name &\multicolumn{2}{|c|}{ Verilog Module Names}&Comments \\ % &&& \\ % \hline % \hline % \begin{libverbatim}mkFIFO % mkFIFOF % mkUGFIFOF % mkGFIFOF\end{libverbatim} % & \te{FIFO2.v}& \te{FIFO20.v}&\\ % \hline % \end{tabular} % \begin{tabular} {|p{1.5in}|p{1in}p{1 in}|p{1.8 in}|} % \hline % \begin{libverbatim}mkFIFO1 % mkFIFOF1 % mkUGFIFOF1 % mkGFIFOF1\end{libverbatim} % & \te{FIFO1.v} & \te{FIFO10.v}&\\ % \hline % \end{tabular} % \begin{tabular} {|p{1.5in}|p{1in}p{1 in}|p{1.8 in}|} % \hline % \begin{libverbatim}mkSizedFIFO % mkSizedFIFOF % mkUGSizedFIFOF % mkGSizedFIFOF % \end{libverbatim} % &\begin{libverbatim}SizedFIFO.v % FIFO1.v % FIFO2.v % \end{libverbatim} % & \begin{libverbatim}SizedFIFO0.v % FIFO10.v % FIFO20.v % \end{libverbatim} % &If the depth of the FIFO = 1, % then \te{FIFO1.v} and \te{FIFO10.v} are used, if the depth = 2, then % \te{FIFO2.v} and \te{FIFO20.v} are used. \\ % \hline % \end{tabular} % \begin{tabular} {|p{1.5in}|p{1in}p{1 in}|p{1.8 in}|} % \hline % \begin{libverbatim} % mkDepthParamFIFOF % mkUGDepthParamFIFOF % mkGDepthParamFIFOF\end{libverbatim} % & \te{SizedFIFO.v} & \te{SizedFIFO0.v}& \\ % \hline % \end{tabular} % \begin{tabular} {|p{1.5in}|p{1in}p{1 in}|p{1.8 in}|} % \hline % \begin{libverbatim}mkLFIFO % mkLFIFOF % mkUGLFIFOF % mkGLFIFOF\end{libverbatim} % & \te{FIFOL1.v} & \te{FIFOL10.v}& \\ % \hline % \hline % \end{tabular} % \end{center} % % Text inserted here to explain anything the user might need to know % % about how the Verilog relates to the BSV they wrote.