0% found this document useful (0 votes)
341 views13 pages

FIFO

This document provides information on FIFO slides including: 1. FIFO basics like put (write), get (read), full and empty signals, and using write and read pointers to track location in the queue. 2. Designing synchronous and asynchronous FIFOs including double sampling reads/writes across clock domains to prevent metastability. 3. Calculating FIFO depth given write and read frequencies/burst sizes, including accounting for idle cycles between reads/writes. 4. Parameterizing FIFO modules and using techniques like fill counts to track full/empty status instead of direct pointer comparisons.

Uploaded by

renju91
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
341 views13 pages

FIFO

This document provides information on FIFO slides including: 1. FIFO basics like put (write), get (read), full and empty signals, and using write and read pointers to track location in the queue. 2. Designing synchronous and asynchronous FIFOs including double sampling reads/writes across clock domains to prevent metastability. 3. Calculating FIFO depth given write and read frequencies/burst sizes, including accounting for idle cycles between reads/writes. 4. Parameterizing FIFO modules and using techniques like fill counts to track full/empty status instead of direct pointer comparisons.

Uploaded by

renju91
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

FIFO Slides:

1. If else logic we may get setup and hold. In case statements we may not get setup and hold. If
else is a priority logic with multiple muxes. Case is a single mux of a larger size.
2. Hash, heap and tree are there in system Verilog and not in Verilog for verification purposes.
Verilog is pure HDL.
3. Stack and queue are the basic data structures for LIFO and FIFO. They use insert and remove.
4. We used circular queues for FIFO, where we can keep writing and reading around the queue.
LIFO are non circular. The size of stack reduces as we read.
5. FIFO Basics: put write get read, full_bar when fifo full empty_bar when empty
6. We use a write pointer and read pointer to know which point we are at. Write pointer points at
next empty location. Read pointer points at last current row to read. It is circular so after read
finishes reading, write can occur at location 4 rather than location 0. Queue pointers always
starts at the bottom of the FIFO.
7. If reader is ahead of the writer, it means the writer wrapped around the memoery.
8. FIFO ports: we add data_in, data_out, wen , ren, F and E. Also we keep wptr and rptr internal
which is a better option. Also it is sequential so we need a clock and reset. Combinational is
difficult for a fifo. It is not easy to control.
9. Multiple read ports: It is a little confusing. One write pointer and many read pointers.
10. When rdptr reaches wtptr then it is empty.
11. When wtptr reaches rdptr it is full.
12. To understand full and empty we have various solutions:
1) Unallocated slots: We leave one slot empty. Wtptr = rdptr -1 buffer is full
Wptr = rdptr then buffer is empty.
2) Fillcount: If 8 depth FIFO, if fillcount = 8 full = 1 fillcount = 0 empty = 1 Here we increment
fillcount for write and decrement for read. It is the best solution.
3) Write and read counts: we have separate counts and wt count rd count if equal to 0 then it
is empty. If 8 for a 8 depth FIFO then full. It is not better than fillcount as we need two
counters.
4) Absolute indices: indices are used instead of pointers. It is confusing.
5) We used use AE and AF. Almost empty and almost full. When 6 or 7 is fillcount then AF = 1.
When 1 or 2 is fillcount then AE = 1. Here we dont need fillcount it will be just wtptr rd ptr
mod 8.
6) Mirroring, we add extra bit to wtptr and rdptr. If the extra bit matches means the FIFO is
empty. If it is different then FIFO is full. It is also called wrap bit.
13. Synchronous same clock. Asynchronous we find it more challenging. We coulf do CDC(clock
domain processing), DVFS(Dynamic voltage frequency scaling) and DPM.
14. FIFO with 2 different clocks will be communicating asynchronously. Any data coming into write
clk from reader side has to be sample and vice versa. The more the sampling less the chance of
metastability(when setup and hold may occur). Using two flip flops is the best option. When one
of the clock domain has high frequency chances of error increase. Then we sample it thrice.
15. Double sampling works as getting two consequent setup violations usually doesnt happen.
16. On reader side we check write ptr sampled. On writer side we check read ptr samples. (wtptrss
and rdptrss).
17. Gray coding is the safest way to ensure less errors as less transitions.
18. To convert binary to gray say 1011: 1 1^ 0 0^1 1^1 which make gray as 1110. So we xor all the
bits except MSB to get gray. For gray: 1110: 1 1^1 1^1^1 1^1^1^0 which makes binary 1011.
So for gray to binary we keep xoring the bit with all the previous bits. Bin[0] =
gray[3]^gray[2]^gray[1]^gray[0] and Bin[1] = gray[3]^gray[2]^gray[1] Only MSB is as it is.
19. FIFO width expansion: here full = F1 or F2. Implementation is about data arrangement.
20. FIFO depth expansion: We could do token passing where we finish one FIFO and then go to next.
Full = Full 1 and Full 2. Ping pong is where we keep going back and forth both the FIFOs.
21. We could have globally asynchronous and locally synchronous.

FIFO questions:

1. Writer: 80 cycles: 1 word/packet next 20 cycles ideal.


Reader: 8 packets consecutively/ cycle and 2 cycles ideal.
Packet: 10K bits
How big is FIFO:
80 written in 100 cycles. In 80 cycles we read 8X8 = 64 packets. In the next 20 ideal cycles, we
have 80 64 = 16 packets to read. So FIFO depth is 16.
If reader: 7 packets/cycle 3 idle. We read 7X8 = 56 read in 80 cycles. In 20 cycles we need to read
80 56 = 24. It will be able to read only 14 in 20 cycles and write again starts to occur. So here
FIFO depth is infinity. If the network gets too busy, we start dropping packets from write.
2. Writer: fw = 100 MHz
Reader: fr = 80 MHz
Burst 80 words per 100 cycles
Time per one word write = 1/100 = 10ns
Time for burst write = 10 X 80 = 800 ns
Time to read one item = 1/80 = 1000/80 = 12.5 ns
No of items read in 800ns is 800/12.5 = 64
So our FIFO depth is 80 64 = 16
3. When we talk about frequency of reader and writer, we are talking about put and get signals
basically because that is what makes us write and read. If the frequencies match that means put
and get have the same frequency and it means FIFO depth is 1 because we read immediately
after it is written
4. When frequency of writer > frequency of reader and burst length is given,
First find the time taken to write burst = (1/fw) * Burst size = Tburst
Then time taken to read one item = 1/fr = Tr
Then FIFO depth = Burst size (Tburst/Tr)
5. Fw>fr with one clock delay between two successive reads and writes is the same as the above. It
is just to create some confusion. FIFO depth maybe 1 extra in this case.
6. If there some no of idle cycle between successive reads and writes, then
First find the time taken to write burst = (1/fw) * Burst size*(1+Idlecyclewrite) = Tburst
Then time taken to read one item = (1/fr) * (1+ Idle cycle read) = Tr
Then FIFO depth = Burst size (Tburst/Tr)
7. If they give duty cycle of wr_enable and read enable it means the same thing as telling us the no
of idle cycles. Duty cycle = 50% means 1 cycle write and 1 cycle idle. (for write)
Duty cycle = 25% 1 cycle read and 3 idle. (for read)
8. If fw<fr, we need a FIFO depth of 1 as it is clear write is slower.
9. If fw<fr or fw= fr and idle cycles for write < idle cycles of read we need to do the entire process
of calculation. If FIFO depth comes as negative means FIFO depth is 1 or infinity. If idle cycles are
same or idle cycles of read<idle cycles of write then FIFO depth is 1.
10. If Writing data = 80Data/100Clock
Reading data 8 Data/10 clock
If burst size is not specified then we assume burst size = 80, here the burst comes only once
So 80 in 100 cycles means FIFO depth = 80 (8X8) = 16. It is 8X8 because we do 8 data each in 10
clock cycles and there are 8 X8 data in 80 clock cycles.
If burst size is 160, we have two bursts. Case 1: write burst 80 idle 20 idle 20 write burst 80
Case2: idle 20 write 80 idle 20 write 80
Case 5: Random idle and random write because it is not a burst. It just does write 80/100.
Here we see FIFO depth = 160 (8X16) = 160 128 = 32
11. We should understand specifications, here I am just adding the example:
Freq A = fre B (assume freq b = 100MHz freq a = 25MHz)
Period(en_B) = period(clk A) *100 (here we understand burst is 100)
Write clk A read clk B
Time to write burst = (1000/25) * 100 = 4000 ns
Duty cycle of B is 25% (means 25% of 4000ns we read and 3000ns we write and dont read)
So 3000ns we are not reading and we need to store. Here 40 ns per write item.
So FIFO depth = 3000/40 = 75
To visualize the write cycle we have 40ns clock period and we have 100 of them inside one read
cycle. Read cycle period is 4000ns. And read cycle duty cycle is 25% so for 1000ns it is 1 and then
3000ns it is 0.

FIFO 1:

1. First mistake which you do is using blocking statements in a sequential logic. Always, always use
non-blocking statements in sequential logic.
2. The Verilog file is not parameter based. To make it parameter based,
Module FIFO1 #(parameter FIFO_depth = 4, POINTER_depth = 2,FIFO_width = 4) (clk,reset, ..);
FIFO1 testbench also has to use parameter so it is
FIFO1 #(.FIFO_depth(4),.POINTER_depth(2),.FIFO_width(4)) FF1(clk,reset..);
3. Here we use FIFO_width*2 because our data is 4 valued logic. {0,1,D,Dbar}. POINTER_depth is
log2 (FIFO_depth). FIFO1 uses fillcount.
4. Here we declare input [FIFO_width*2-1:0] data_in; And same value register size for output
data_out. We also output empty_bar, full_bar and [POINTER_depth:0] fillcount. Fillcount is
always one bit extra. The other varianles are [POINTER_depth-1:0] wptr,rptr. And a
[FIFO_width*2-1:0] FIFO [0:FIFO_depth-1];
5. Then we start always @ (posedge clk)
If reset then we set wptr and rptr as 0 and fillcount is 0. Data out is x and emptybar and fullbar is
1. Else if reset = 0 then we do four if begin end statements. First we check if put = 1 and full_bar
= 1, if so then FIFO[wptr] <= data_in. wptr and fillcount is incremented by 1.
If fillcount is equal to FIFO_depth fullbar is 0 else 1.
Then we check if get =1 and empty_bar = 1, if so then data_out = FIFO[rptr]. rptr is incremented
by 1 and fillcount is decremented by 1.
If fillcount is 0, emptybar is 0 else 1.
6. So the basic idea here is fillcount is incremented when write occurs and decremented when read
occurs. Fillcount = fifo depth then full is 1. Fillcount = 0 then empty is 1. Write pointer
incremented when we write. Read pointer incremented when we read.
7. In testbench we check read, write. In synthesis we get one module as there only one always
block. It completely contains gates and wires. In the same cycle we can have put = 1 and get = 1
sp read and write can occur in the same clock.

FIFO2:

1. We have the same parameters, inputs and outputs here as FIFO1 except we dont have fillcount.
We have AE and AF which are almost empty and almost full.
2. At reset = 1, we set AE and AF as 0. If reset is 0,
if put = 1 and full_bar = 1, if so then FIFO[wptr] <= data_in. wptr is incremented by 1.
If wptr-rptr == 0 and AF = 1, then full_bar 0 else 1.
If (wptr rptr == FIFOdepth-1 or FIFOdepth-2) then AF is 1 else 0. (here we use FIFOdepth
parameter as the module has varying parameters)
if get =1 and empty_bar = 1, if so then data_out = FIFO[rptr]. rptr is incremented by 1.
If wptr-rptr == 0 and AE = 1, then empty_bar 0 else 1.
If (wptr rptr == 1 or 2) then AE is 1 else 0.
3. The main concept here is that AE and AF indicate we have reached one end. So if wptr and rptr
reach each other either AE or AF will be 1 and that will indicate that fifo is empty or full.
4. This is a good method as we need just one bit regs for AE and AF. But we compare here so
comparison units may add to area. But we also compare fillcount so area difference may not be
a lot. We need a subtractor for wptr and rdptr.

FIFO3:

1. We have the same parameters, inputs and outputs here as FIFO1 except we use mirroring
technique here. Here [POINTER_depth:0] wptr,rptr instead of [Pointer_depth-1:0]. No additional
fillcount or AE AF.
2. At reset = 1, we set the usual. If reset is 0,
if put = 1 and full_bar = 1, if so then FIFO[wptr[POINTERdepth-1:0]]<= data_in. wptr is
incremented by 1.
If (wptr[pointerdepth] != rptr[pointerdepth] and wptr[pointerdepth-1:0] == rptr[pointerdepth-
1:0] then fullbar is 0 else 1
if get =1 and empty_bar = 1, if so then data_out = FIFO[rptr[POINTERdepth-1:0]]. rptr is
incremented by 1.
If wptr == rptr then emptybar is 0 else 1.
3. So here the method is to check the extra bit to know if it is full or empty. Extra bit if it doesnt
match for wptr and rptr then full else if the extra bit matches then empty.

FIFO 2 clocks:

1. First lets understand the concept. We want to double sample the pointers because we have two
different clocks. Before sampling a pointer we first convert it to gray. After sampling, we need to
check for empty and full flags. To check those we need to convert the sampled pointer from gray
back to binary. In read clock we sample read pointer. In write clock we sample write pointer.
2. Lets call FIFO depth: FD Pointer depth: PD FIFO width: FW
3. Here we assume a 2 value system.
4. We have all [PD:0] wptr,wptr1,wptrs.wptrss1,wptrss2,
[PD:0] rptr,rptr1,rptrs,rptrss1,rptrss2
We are using the n+1 method. This is the mirroring method.
5. We have two clks, rclk and wclk. We sample rptr in wclk and wptr in rclk.
In posedge wclk,
If (reset == 1) wptr =0 rptrs = 0 rptrss = 0
Else
Rptrss1 <= rptrs
Rptrs <= rptr1
if put = 1 and full_bar = 1, if so then FIFO[wptr[POINTERdepth-1:0]]<= data_in. wptr is
incremented by 1.
In posedge rclk,
If (reset == 1) rptr =0 wptrs = 0 wptrss = 0 data_out = 0
Else
wptrss1 <= wptrs
wptrs <= wptr1
if get= 1 and empty_bar = 1, if so then data_out <= FIFO[rptr[POINTERdepth-1:0]]. rptr is
incremented by 1.
6. Empty_bar, full_bar are combinational and dont depend on clk. Empty_bar depends on rclk so
we check with rptr and wptrss2. Rptr is ptr before converting to gray. Wptrss2 is ptr after
sampled is converted to binary.
Empty_bar = (wptrss2 == rptr) ? 0:1;
Full_bar depends on wptr and rptrss2.
Full_bar = ((wptr[3]!= rptrss2[3]) && (wptr[2:0] == rptr[2:0])) ? 0:1;
7. Then we assign
Wptr1 = btog(wptr)
Rptr1 = btog(rptr)
Wptrss2 = gtob(wptrss1)
Rptrss2 = gtob(rptrss1)
8. We then write the functions to be used binary to gray and vice versa
Function [2:0] btog;
Input [2:0] ptr;
Begin
Btog[0] = ptr[0] ^ ptr[1];
Btog[1] = ptr[1] ^ ptr[2];
Btog[2] = ptr[2];
End
endfunction

Function [2:0] gtob;


Input [2:0] ptr;
Begin
Gtob[0] = ptr[0] ^ ptr[1]^ ptr[2];
Gtob[1] = ptr[1] ^ ptr[2];
Gtob[2] = ptr[2];
End
Endfunction
9. As we are sampling twice we get the full_bar one clock cycle late and empty_bar one clock cycle
late.
10. If we use the AE and Af method we have additional,
assign AF = ((wptr - rptr_ss2 == 3'b110) || (wptr - rptr_ss2 == 3'b111))? 1 : 0;
assign AE = ((wptr_ss2 - rptr == 3'b001) || (wptr_ss2 - rptr == 3'b010))? 1 : 0;
AF uses wptr and rptrss2. AE uses rptr and wptrss2.

LIFO:

1. LIFO basic parameters are like FIFO. Here we use pushptr and popptr. reg [LIFO_WIDTH - 1:0]
LIFO [0:LIFO_DEPTH - 1];
2. If reset = 1, full = 0 and empty = 1. Pushptr and popptr are 0.
If reset = 0,
If push is 1 and pushptr<LIFOWIDTH-1 and full == 0
Then full = 0 empty = 0, LIFO[pushptr] = din. Pushptr is incremented by 1. And popptr = pushptr
Else if push is 1 pushptr is LIFOWIDTH -1 and full is 0,
Then full = 1 empty = 0, LIFO[pushptr] = din. And popptr = pushptr. We cant further increase
pushptr.
Else we do nothing
If pop is 1 and popptr>0 and empty == 0
Then full = 0 empty = 0, dout = LIFO[popptr] . Popptr is decremented by 1. Pushptr = popptr + 1
Else If pop is 1 and popptr==0 and empty == 0,
Then full = 0 empty = 1, dout = LIFO[popptr] . Popptr is decremented by 1. Pushptr = popptr
Else we do nothing
3. popptr = popptr - 1; pushptr = popptr + 1; uses blocking statements but if we want non blocking
statements we can make it as popptr <= popptr - 1; pushptr <= popptr; Then we can make all
non blocking statements in the sequential logic block.
4. LIFO is the simplest. Pushptr is always ahead of popptr unless at the beginning or end. Always
use non blocking for sequential logic.

FIFO Depth Expansion:

1. We have in built FIFOs which have fifodepth as 8


2. Outfile = fifodepth.v $fifodepth = $ARGV[0] (input entered by user)
3. First $x = $fifodepth/8; initially xflag should be 1.
while(($x > 1) && ($xflag == 0)){
if ($x%2 == 0){
$x = $x/2;
$xflag = 0;
}
else{
$xflag = 1;
}
} //Here we want to test if fifowidth is divisible by 2 and completely as we want it to be a power
of 2. So we keep divinding by 2 until 1.//
if ($fifodepth == 8){
$xflag = 0;
}
We print invalid if xflag is 1 or if fifodepth < 8.
4. First, $x = fifodepth/8. Then we print all the basics like module inputs and outputs.
5. We declare variables like integer writetoken=0; integer readtoken = 0; integer wptr = 0; integer
rptr = 0; write token and read token are integers as no of fifos are variant and integer gives us
ease in increase the no.
6. Then we print wire (and declare all the variables we need.
foreach my $i (0..$x-1){
if ($i < ($x-1)){
print $of "full_bar",$i,",";
}
else {
print $of "full_bar",$i,";\n";
}
} //It prints fullbar0,fullbar1; etc
IIly we do wire print and then foreach for empty_bar, put and get.
7. Then we need to use instance of library defined FIFO so we use
foreach my $j (0..$x-1){
print $of "FIFO FF$j(clk,reset,put$j,get$j,data_in,empty_bar$j,full_bar$j,data_out);\n";
}
8. Then we print always begin
9. Now we start the code. Here we are using token system. Write token and read token separate.
10. This is the piece of Verilog code:
if (wptr == 16) begin writetoken = 0; wptr = 0; end
else if (wptr >= 8) begin writetoken = 1; end
else if (wptr >= 0) begin writetoken = 0; end //We will now write a piece of perl code for printing
this.
First $n = fifodepth/8 $mult = 8 * $n
Then we print out
if (wptr == $mult) begin writetoken = 0; wptr = 0; end
Then we do a if statement where if $n > 1 we run a for loop.
for ($j=$n - 1; $j >= 0; $j--) {
$mult = $j * 8;
//Printing code
} //This prints from wptr = 8 and wptr = 0
It prints
else if (wptr >= $mult) begin writetoken = 1; end
else if (wptr >= $mult) begin writetoken = 0; end
11. Next is Put assignment:
We want to print:
if (writetoken == 0) begin put0 = put; put1 = 0; end
else if (writetoken == 1) begin put0 = 0; put1 = put; end
So we do print $of "if (writetoken == 0)\nbegin\n";
for my $l (0..$n-1){
if ($l == 0){
print $of "put$l = put;\n";
}
else{
print $of "put$l = 0;\n";
}
} //Here its self explanatory .
if ($n > 1){
for my $k (1..$n-1){
print $of "else if (writetoken == $k)\nbegin\n";
for my $l (0..$n-1){
if ($l == $k){
print $of "put$l = put;\n";
}
else{
print $of "put$l = 0;\n";
}
}
print $of "end\n";
}
} //Here we want to make sure n > 1 then we make the else if statements. $k starts with 1
as we already finished for writetoken = 1. $l to get values for all puts in this new fifo.
12. We repeat the same methods for read token and get assignment.
13. Now we need to do full_bar and empty_bar generation:
$n = fifodepth/8
print $of "full_bar = "; if ($n > 1) for my $d (0..$n-2){
print $of "full_bar$d & ";
} //We print till n-2 as that is second last.
Then print $of "full_bar$nminus;\n"; (nminus = $n -1 )
Then we follow the same method for empty_bar.
14. Then to complete the module,
print $of "if ((put == 1) && (full_bar == 1))\nbegin\nwptr = wptr + 1;\nend\n";
print $of "if ((get == 1) && (empty_bar == 1))\nbegin\nrptr = rptr + 1;\nend\n";
print $of "\nend\n";
print $of "endmodule";
15. So the concept here is we print out wires for $n of full bar, empty bar, put and get.
16. Then e print out the instances depending on $n.
17. Then in the always block,
Based on wptr we change writetoken. If wptr is 16 it means it finished a wrap around and hence
writetoken = 0 meaning go to first FIFO. If wptr >= 8 then it finished FIFO 1 and hence writetoken
= 1. Similarly with read token.
18. Next based on token can tell which FIFO gets the put and get.
19. Then fullbar and empty bar are ands of all empty bar and full bar.
20. Incrementing wptr and rptr depends only on put and fullbar, get and emptybar respectively.
21. The perl helps print. The extra thing we do there is that we need to make sure if and else if has a
difference in printing. Also last input and rest of the inputs difference.

FIFO Width Expansion:

1. $datawidth = $ARGV[0];
Outfile = fifowidth.v;
$datawidth = 2 * $datawidth;
It is a 4 valued logic.
$n = $datawidth;
2. We make an array. Here we use dynamic programming. We have the widths 5,12 and 16. So
array contains no of redundant or extra bits we have if we use these FIFO widths.
Array[0] = 0 (as we are using none) also for calculations it helps to have array[0] as 0.
Array[1] = 4 = 5-1 (we need 1 FIFO5)
Array[2] = 3 = 5-2 (we need 1 FIFO5)
Array[3] = 2 = 5-3 (we need 1 FIFO5)
Array[4] = 1 = 5-4 (we need 1 FIFO5)
Array[5] = 0 = 5-5 (we need 1 FIFO5)
Array[6] = 4 = 10 6 (we need 2 FIFO5)
Array[7] = 3 = 10 7 (we need 2 FIFO5)
Array[8] = 2 = 10 8 (we need 2 FIFO5)
Array[9] = 1 = 10 9 (we need 2 FIFO5)
Array[10] = 0 = 10 10 (we need 2 FIFO5)
Array[11] = 1 = 12-1(we use FIFO 12)
Array[12] = 0 (we use FIFO12)
Array[13] = 2 = 15 -13 (we use 3 FIFO5)
Array[14] = 1 = 15-14 (we use 3 FIFO5)
Array[15] = 0 = 15-15 (we use 3 FIFO5)
Array[16] = 0 (we use 1 FIFO16)
After the array is made we can use it to do more.
3. If data width < 1 print INVALID else
4. Print module input,output.
In this instead of wire data_in is input and data_out is output.
5. We start the code, we first need to get all the array values for 17..$n-1. Which is if datawidth is
say 19, we run a for loop for 17..18
$k = $m. We run a while loop ($k > 0)
We see three ways of moving:
If (k-15) > 0 (We consider one value lesser because if k = 16 we want it to go into k-15 > 0)
Else (k-11) > 0
Else (k-4) > 0
Inside them we have 3 paths. We want to go to the path which gives us the least redundant bits.
Initially when we get $k we want to check if it is >=16, >=12, >=5 or <5.
Inside each of them we need to again check.
If (k>=16) => (k-15) >0
Initially flag 5 = 1
If array(k-12) < = array(k-5) flag12 =1
Because that means 12 offers a better path. If array(k-16) <= array(k-12) and <= array(k-5) then
flag16=1. Means 16 offers a better path.
Now we check if flag5 = 1 else flag12 = 1 else flag16 = 1
Whichever flag is set k=k-5,k-12,k-16 respectively.
If k=0, array[$m] = 0. We write this in each k-15 k-11 etc. as when k=0 we quit the loop and we
wouldnt get array[$m] value.
That was for k-15 >0
For k-11>0
We test flag 12 conditon
If (k=0) condition
For k-5>0
No test flag5=1
K=k-5
If (k=0) condition
Else
Flag5=1
And if (k=5) array[$m] = 0
Else array[$m] = 5-$k;

6. After everything we repeat same method for $n. $k =$n. Except for one difference: based on flag
amd (k-11),(k-15), (k-4) and else etc. We make another array arraynos with $l = 0 initially.
If flag16 =1 arraynos[$l] = 16
$l = $l + 1
Else if flag 12 = 1 arraynos[$l] = 12
$l=$l + 1
7. Now that we have figured out the redundant bits and what FIFOs to use, we do datawidthminus
which datawidth + array[n] -1 (array[n] gives us the redundant bits) Here we print input and
output with datawidthminus:0 size.
8. $l gives us the no of FIFOs we have.
print $of "wire ";
foreach my $i (0..$l-1){
if ($i < ($l-1)){
print $of "full_bar",$i,",";
}
else {
print $of "full_bar",$i,";\n";
}
} // For printing wire full_bar1,full_bar0 etc. Same method for empty bar.

9. Check this diagram: (to understand dynamic programming)


In this diagram we start with 18 as the no. We see 3 paths. We pick the lowest one and look
what paths available there and so on. This diagram clearly shows whats happening.

10. Here is the code for generating instances of the FIFOs


my $c = 0;
my $no1;
for my $b (0..$l - 1){ //We do it for $l times which gives no of FIFOs
$no1 = $c + $arrnos[$b] - 1; // we add arrnos[b] -1 because it tells us how many bits we
need to add. Eg: if FIFO5 then arrnos is 5. So we want to add 4. $c tells us at what point we are.
print $of "FIFO$arrnos[$b]
FF$b(clk,reset,put,get,data_in[$no1:$c],empty_bar$b,full_bar$b,data_out[$no1:$c]);\n";
$c = $c + $arrnos[$b];
}
11. Full bar and empty_bar generation: my $lminus = $l - 1; print $of "full_bar = ";
for my $b (0..$l-2){ print $of "full_bar$b & "; }
print $of "full_bar$lminus;\n"; print $of "empty_bar = ";
for my $b (0..$l-2){ print $of "empty_bar$b & "; }
print $of "empty_bar$lminus;\n";
print $of "end\n";
print $of "endmodule";
Here $b tells which full_bar and which empty_bar.
12. Example for the entire code:
Datawidth = 2*34
We first run the for loop for 17..33
Then we get $k = 34
If we see in the dynamic programming way,

34 -> (k-15 > 0) condition works


34 can go three ways arr[29] arr[22] arr[18] which is 0,0,2. So we pick 12 path which is 22.
K=k-12 = 34-12 =22. Here arrnos[0] = 12
22 -> (k-15 0) can go three ways arr[17] arr[10] arr[6] which are 0,0,4. So the lowest path is 10
as it is arr[10] = 0 and 12 value is higher than 5.
K = k 12 = 22-12 = 10 Here arrnos[1] = 12
k-4>0 condition works here so,
10 can go only one path k = k-5 =5. Arrnos[2] = 5
k-4>0 works here so
k = k-5 = 5-5 = 0 Now as k=0, we note array[$n] = 0 and arrnos[3] = 5.
So FIFOs are (12,12,5,5).
Then we print
//Original data_width entered is 17
//The datawidth is twice the entered datawidth as it is a four valued logic
module FIFO_depth_expansion(clk,reset,put,get,data_in,empty_bar,full_bar,data_out);
input put,get,reset,clk,data_in;
output reg data_out,empty_bar,full_bar;

parameter data_width = 34;


//Redundant Bits are 0
input [33:0]data_in;
output [33:0]data_out;
wire full_bar0,full_bar1,full_bar2,full_bar3;
wire empty_bar0,empty_bar1,empty_bar2,empty_bar3;

After that we reach the instance part,


C = 0 b= 0
No = c + arrnos[b] -1 = 0 + 12 -1 =11
Print FIFOarrnos[0] FF$b data_in[no:c] empty_bar$b
Which is FIFO12 FF0 data_in[11:0] empty_bar0
C=12
B=1
No = 12 + 12 -1 = 23
C=24
B=2
No = 24+5-1 = 28
C=29
B=3
No = 29+5-1 = 33
C=34

So the rest of the file looks like


FIFO12 FF0(clk,reset,put,get,data_in[11:0],empty_bar0,full_bar0,data_out[11:0]);
FIFO12 FF1(clk,reset,put,get,data_in[23:12],empty_bar1,full_bar1,data_out[23:12]);
FIFO5 FF2(clk,reset,put,get,data_in[28:24],empty_bar2,full_bar2,data_out[28:24]);
FIFO5 FF3(clk,reset,put,get,data_in[33:29],empty_bar3,full_bar3,data_out[33:29]);
always @(*)
begin
full_bar = full_bar0 & full_bar1 & full_bar2 & full_bar3;
empty_bar = empty_bar0 & empty_bar1 & empty_bar2 & empty_bar3;
end
endmodule

You might also like