FPGA digital system design (10)-data communication fifo

In the implementation of FIFO implementation, the incoming data is read first, similar to a barrel, and the output first put in from the input terminal will be output from the output terminal first. According to different clock domains, it can be divided into synchronous FIFO and asynchronous FIFO.
1.
RTL circuit diagram of synchronous FIFO design

Insert picture description here

module FIFO_SAME(data_in, rd, wr, reset, clock, data_out, full, empty);
input [7:0] data_in;
input rd, wr, reset, clock;
output [7:0] data_out;
output full, empty;
wire [7:0] data_out;   //
reg full_in, empty_in;
reg [7:0] mem [15:0];
reg [3:0] rp, wp;   //读写指针
assign full = full_in;
assign empty = empty_in;
assign data_out = mem[rp];
always@(posedge clock)begin  //正常写入数据
 if(wr && ~full_in)
 mem[wp] <= data_in;
end
always@(posedge clock or negedge reset)begin
 if(!reset)
 begin
  wp <= 0;
 end
 else
 begin
  if(wr && ~full_in)
   wp <= wp + 1'b1;
 end
end
always@(posedge clock or negedge reset)begin
 if(!reset)
 begin
  rp <= 0;
 end
 else
 begin
  if(rd && ~empty_in)
  rp <= rp + 1'b1;
 end
end
always@(posedge clock or negedge reset)begin
 if(!reset)
 begin
  full_in <= 1'b0;
 end
 else
 begin
  if((~rd && wr)&&((wp == rp - 1)||(rp == 4'h0 && wp == 4'hf)))
  full_in <= 1'b1;
  else if(full_in && rd)
  full_in <= 1'b0;
 end
end
always@(posedge clock or negedge reset)begin
 if(!reset)
 begin
  empty_in <= 1'b1;
 end
 else
 begin
  if((rd && ~wr) && (rp == wp - 1 || (rp == 4'hf && wp == 4'h0)))
  empty_in <= 1'b1;
  else if (empty_in && wr)
  empty_in <= 1'b0;
 end
end
endmodule

Simulation circuit
Insert picture description here

2. Asynchronous FIFO design
One of the leading ideas of today's integrated circuit design is synchronous design, that is, all control devices (such as flip-flops, RAM, etc.) are controlled by the same clock. However, in actual application systems, it is very difficult to achieve complete synchronization design, which is prone to clock deviation. The clock deviation approximately proportional to the inline delay becomes an important part of the clock cycle, and the cross-chip communication in the synchronous design requires more than one clock cycle. In the design of integrated circuits, there is often no need to adopt a single clock as a whole, thus completely avoiding the problem of clock uncertainty. Such a system often contains several clocks.

However, a problem brought by multiple clock domains is that it is inevitable to complete the transfer of data between different clocks (such as data transfer between high-speed modules and low-speed modules). However, in the design of multiple clock domain systems, different clocks Data transfer between domains must still be resynchronized. The usual approach is to add a handshake signal to each bit signal to solve this problem, but this will increase the complexity of the system and affect the transmission speed. Asynchronous FIFO (First In First Out) is a simple and quick solution to this problem.

In asynchronous circuits, because the cycle and phase of the clocks are completely independent, the probability of data loss is not zero. How to design a highly reliable, high-speed asynchronous FIFO memory becomes a difficult point. At the same time, the overlapping part of the two clock domains: the generation of full and empty states is also one of the key points of the design.
Insert picture description hereThe ports and functions of the top-level module are shown in the figure below. Insert picture description here
Metastable processing When
a trigger enters the metastable state, it is impossible to predict the output level of the unit, nor can it predict when the output will stabilize at a certain correct level. . During this stable period, the flip-flop outputs some intermediate levels, or may be in an oscillating state, and this useless output level can propagate along the cascade mode of each flip-flop on the signal path. The metastable state is generated because in the synchronous circuit system, if the setup time or hold time of the trigger is not satisfied, the metastable state may occur. At this time, the trigger output Q is in the metastable state, which means that the trigger cannot be Reach a confirmable state within a certain period of time. Logic misjudgment may enlarge the fault surface and cause subsequent catastrophic consequences of the circuit.

The setup time is the time that the data input must be valid before the clock flips.
The hold time is the time that the output must still be valid after the clock edge.
When a signal is stored in the register, if this requirement is not met between the signal and the clock, the value of Q is uncertain, and will remain at a high level or a low level when it is unknown. At this time, the register enters the metastable state (Metasability). The solution to metastability is to add a synchronizer to make the signal stable enough when sampling in another clock domain.
The synchronizer generally uses a two-stage synchronizer. The first-stage synchronizer is still prone to metastable state, and the two-stage synchronizer has a waiting time to wait for the clock cycle. This kind of synchronizer can synchronize some metastable values ​​to a certain value, but it is not necessarily the correct value. At the same time, some metastable states still cannot be stabilized to a certain value. This situation becomes a synchronization error. Due to the random nature of synchronization errors, it is difficult to track them. If you want to further reduce the probability of metastability, you can increase the number of synchronizers, but too many synchronizers will degrade the performance of the system, so there will not be too many synchronizers in the system. Generally, two synchronizers are used. One synchronizer is enough.
Insert picture description here

The main difficulty of asynchronous FIFO is the judgment of the empty and full state.
If the writing circuit wants to judge whether the current FIFO is full, it needs to compare the writing pointer maintained by the writing circuit itself with the reading pointer maintained by the reading circuit. This read pointer needs to be sent in In the write circuit, the problem of passing through the clock domain occurs at this time, that is, the read pointer needs to be synchronized from the read clock domain to the write clock domain, and then participate in the judgment. At this time, the synchronizer described above is needed.
Similarly, for the empty state, this is the state that the readout circuit cares about and is also maintained by the readout circuit. If the read circuit judges whether the current FIFO is empty, it needs to take the write pointer in the clock domain to the read clock domain, and compare it with the read pointer in the read clock domain to determine whether it is empty, which also crosses the clock domain.
In the cross-clock domain system, it is hoped that the probability of error is as low as possible. At this time, Gray code is undoubtedly the best choice. Because Gray code is a reliability code, it is a code that minimizes errors, and it greatly reduces the confusion of the circuit from one state to the next. Since this code value changes one bit, it is more reliable to change two bits at the same time with other codes.
The corresponding relationship between Gray code and binary code is shown in the figure below:
Insert picture description here

From the previous introduction, it can be seen that the stable value after passing through the synchronizer may be 1 or 0, and may be the same as the input value or may be different from the input value. For example, if the decimal number is changed from 7 to 8, the binary code is changed from 0111 to 1000. After 0111 is sent to the synchronizer, since 4 is all changed, all 4 bits may appear in a metastable state, so that the output of the synchronizer There will be various possibilities, so even if the data is stable, the effect on the entire circuit is very small. If the Gray code is used, it is changed from 0100 to 1100, but the high bit has changed, and only this bit may appear in a metastable state. After processing by the synchronizer, there are only two possible values ​​at the output: 0100 or 1100 is the correct value. If you get this output, it is naturally the best, but even if you get the output of 0100, it is just the same as the original value. It can be considered that there is no change, and this will not have a negative impact on the circuit. Compared to the situation where any value is possible after the binary code changes, Gray code is obviously a more acceptable encoding method.

Although the Gray code has a better effect in cross-clock domain, it is insufficient in its own counting. That is to say, it is necessary to convert the Gray code into a binary code to count. The code part of the Gray code to binary code of thinking is as follows:

bin[0] = gary[3] ^ gary[2] ^ gary[1] ^ gary[0] ;
bin[1] = gary[3] ^ gary[2] ^ gary[1] ;
bin[2] = gary[3] ^ gary[2] ;
bin[3] = gary[3] ;

This structure can also be converted into a for loop to complete, such as written in the form of a module, the code is as follows

module gray2bin(bin, gray);
parameter SIZE = 4;
output [SIZE - 1:0]bin;
input [SIZE - 1:0]gray;
reg [SIZE - 1:0] bin;
integer i;
always@(gray)
for(i = 0, i, SIZE; i = i + 1) ;
bin[i] = ^(gray >> 1);
endmodule 

After counting, it will be changed back to Gray code, and the conversion method is similar to the above method.
Then there is the focus: determining the status of full air
for a method to determine the binary state of empty full
empty state: When the same value of the read and write pointers, the read pointer and the write pointer considered experienced the same number of cycles, that FIFO The memory is in empty state.
Full state: If the two pointers are different except for the highest bit, the rest of the bits are the same, it is considered that the write pointer has circulated one more time than the read pointer, which indicates that the FIFO memory is full.
The judgment of the above empty or full state is only feasible for binary pointers, but it cannot be used for Gray code pointers at all.
Gray code empty and full state judgment
Empty state : When the value of the read pointer and the write pointer are the same, it is considered that the read pointer and the write pointer have gone through the same number of cycles, that is to say, the FIFO memory is in the empty state, and the binary empty state is judged The method has been.
Full state :
1. The highest bit of the read pointer and the write pointer are not the same;
2. The XOR value of the first two bits of the
read pointer is consistent with the XOR value of the first two bits of the write pointer; 3. The remaining positions of the read pointer and the write pointer The values ​​are exactly the same.

Next is the design of each sub-module of asynchronous FIFO:
the FIFO designed this time is divided into five sub-modules, namely: read pointer control module, write pointer control module, memory RAM module, read pointer synchronization to write clock domain module and write The pointer is synchronized to the read clock domain module.

The first is the sub-module code that synchronizes the read pointer to the write clock domain:

/* time:  20200828
 主要功能:fifo子模块,读指针同步到写时钟域模块代码
 端口定义:wrptr2: 写时域读指针
    rptr:  写指针
    wclock: 写时钟
    wreset: 写复位  
=========================================================*/
module sysc_r2w(wrptr2, rptr, wclock, wreset);
parameter ADDRSIZE = 4;
input [ADDRSIZE:0] rptr;        //同步前的读指针
input wclock, wreset;     
output [ADDRSIZE:0] wrptr2;     //同步后的读时针
reg [ADDRSIZE:0] wrptr2;
reg [ADDRSIZE:0] wrptr1;    //中间的寄存器
always@(posedge wclock, negedge wreset)begin
 if (!wreset)
 begin
  {
    
    wrptr2, wrptr1} <= 0;
 end
 else
 begin
  {
    
    wrptr2, wrptr1} <= {
    
    wrptr1, rptr} ;//两个寄存器之间进行连接
 end
end
endmodule

The RTL circuit is shown in the figure:
Insert picture description here

Next is the sub-module whose write pointer is synchronized in the read clock domain

/*time:   2020.8.28。
  主要功能: fifo子模块,写指针同步到读时钟域模块代码
  端口定义: rwptr2: 读时域写指针
    wptr:  写指针
    rclock: 读时钟
    rreset: 读复位
================================================================*/
module syse_w2r(rwptr2, wptr, rclock, rreset);
parameter ADDRSIZE = 4;
input [ADDRSIZE:0] wptr;        //同步前的写指针
input rclock, rreset;     
output [ADDRSIZE:0] rwptr2;     //同步后的写时针
reg [ADDRSIZE:0] rwptr2;
reg [ADDRSIZE:0] rwptr1;    //中间的寄存器
always@(posedge rclock, negedge rreset)begin
 if (!rreset)
 begin
  {
    
    rwptr2, rwptr1} <= 0;
 end
 else
 begin
  {
    
    rwptr2, rwptr1} <= {
    
    rwptr1, wptr} ; //两个寄存器之间进行连接
 end
end
endmodule

The RTL circuit is shown in the figure:

Insert picture description here
Next is the judgment of the empty state:

/* time:  20200828
   主要功能:fifo子模块,读指针电路以及读空控制逻辑电路
 端口定义: rempty:读空标志
     raddr: 读地址
     rptr:  读指针
     rwptr2:读时域同步写指针 
     rinc:  读使能
     rclock:读时钟
     rreset:读复位
=========================================================================*/
module rptr_empty(rempty, raddr, rptr, rwptr2, rinc, rclock, rreset);
parameter ADDRSIZE = 4;
input rinc, rclock, rreset;
input [ADDRSIZE:0] rwptr2;
output [ADDRSIZE - 1:0] raddr;
output [ADDRSIZE:0] rptr;
output rempty;
reg rempty;
wire [ADDRSIZE - 1:0] raddr;
reg [ADDRSIZE:0] rptr;
reg [ADDRSIZE:0] rbin, rgnext, rbnext;
reg raddrmsb;
integer i;
always @(posedge rclock or negedge rreset)begin
 if(!rreset)
 begin
  rptr <= 0;
  raddrmsb <= 0;
 end
 else
 begin
  rptr <= rgnext;
  raddrmsb <= rgnext[ADDRSIZE]^rgnext[ADDRSIZE-1];
 end
end
always @(rptr or rinc)begin
 for (i = 1 ; i <= ADDRSIZE ; i = i + 1)
 begin
  rbin[i] =^(rptr >> i);
 end
 if(!rempty)
 begin
  rbnext = rbin + rinc;
 end
 else
 begin
  rbnext = rbin;
 end
 rgnext = (rbnext >> 1)^rbnext; 
end
always @(posedge rclock or negedge rreset)begin
 if(!rreset)
 begin
  rempty <= 1'b1;
 end
 else
 begin
  rempty <= (rgnext == rwptr2);
 end
end
assign raddr = {
    
    raddrmsb, rptr[ADDRSIZE - 2:0]};
endmodule

The RTL circuit is shown in the figure
Insert picture description here

Next is the full state judgment:

/* time:     20200828
   主要功能: fifo子模块,写指针电路以及写满控制逻辑电路
 端口定义: wfull: 写满标志
     waddr: 写地址
     wptr:  写指针
     wrptr2:写时域同步读指针 
     winc:  写使能
     wclock:写时钟
     wreset:写复位
==============================================================================*/
module wptr_full(wfull, waddr, wptr, wrptr2, winc, wclock, wreset);
parameter ADDRSIZE = 4;
input winc, wclock, wreset;
input [ADDRSIZE:0] wrptr2;
output [ADDRSIZE - 1:0] waddr;
output [ADDRSIZE:0] wptr;
output wfull;
reg wfull;
wire [ADDRSIZE - 1:0] waddr;
reg [ADDRSIZE:0] wptr;
reg [ADDRSIZE:0] wbin, wgnext, wbnext;
reg waddrmsb;
wire w_2ndmsb, wr_2ndmsb;
integer i;
always @(posedge wclock or negedge wreset)begin
 if(!wreset)
 begin
  wptr <= 0;
  waddrmsb <= 0;
 end
 else
 begin
  wptr <= wgnext;
  waddrmsb <= wgnext[ADDRSIZE]^wgnext[ADDRSIZE-1];
 end
end
always @(wptr or winc)begin

 for (i = 1 ; i <= ADDRSIZE ; i = i + 1)
 begin
  wbin[i] =^(wptr>> i);
 end
 if(!wfull)
 begin
  wbnext = wbin + winc;
 end
 else
 begin
  wbnext = wbin;
 end
 wgnext = (wbnext >> 1)^wbnext; 
end
assign w_2ndmsb = wgnext[ADDRSIZE] ^ wgnext[ADDRSIZE - 1];
assign wr_2ndmsb = wrptr2[ADDRSIZE] ^ wrptr2[ADDRSIZE - 1];
always @(posedge wclock or negedge wreset)begin
 if(!wreset)
 begin
  wfull <= 1'b0;
 end
 else
 begin
  wfull <= ((wgnext[ADDRSIZE] !== wrptr2[ADDRSIZE]) && (w_2ndmsb == wr_2ndmsb) &&(wgnext[ADDRSIZE - 2 : 0] == wrptr2[ADDRSIZE - 2:0]));
 end
end
assign waddr = {
    
    waddrmsb, wptr[ADDRSIZE - 2:0]};
endmodule

The RTL circuit is shown in the figure:
Insert picture description here

Next is to read the data in the RAM memory and write data to the RAM memory:

/*time:  20200828。
  主要功能: fifo子模块存储模块
  端口定义: rdata:读出数据
    wdata:写入数据
    waddr:写地址
    raddr:读地址
    wclock:写时钟
    rclock:读时钟
    wclken:写使能
    rclken:读使能
=============================================================================*/
module fifomem(rdata, wdata, waddr, raddr, wclock, rclock, wclken, rclken);
parameter DATASIZE = 8;
parameter ADDRSIZE = 4;
input wclken, wclock, rclken, rclock;
input [DATASIZE - 1:0] wdata;
input [ADDRSIZE - 1:0] waddr, raddr;
output [DATASIZE - 1:0] rdata;
reg [DATASIZE - 1:0] rdata;
reg [DATASIZE - 1:0] MEM [0:(1<<ADDRSIZE) - 1];
always @(posedge rclock)begin
if (rclken)begin
 rdata = MEM[raddr];
end 
else ;
end
always @(posedge wclock)begin
if (wclken)begin
 MEM[waddr] = wdata ;
end
else ;
end
endmodule

The RTL circuit is shown in the figure:
Insert picture description here
read data and write data are simulated separately, the simulation circuit diagram is as follows:
Insert picture description hereFinally, the top module:

/* time:  20200828
 主要功能:fifo顶层模块,实现异步fifo的通讯功能,主要通过输入指定内容给fpga,
      再通过读操作将输入值返回。
 端口定义:rdata:读出数据
    wfull:写满标志
    rempty:读空标志
    wdata:写入数据
    winc:写使能
    wclock:写时钟
    wreset:写复位
    rinc:读使能
    rclock:读时钟
    rreset:读复位    
===============================================================*/
module fifo_asyn(rdata, wfull, rempty, wdata, winc, wclock, wreset, rinc, rclock, rreset);
parameter ADDRSIZE = 4;
parameter DATASIZE = 8;
input wclock, winc, wreset;
input rclock, rinc, rreset;
input [DATASIZE - 1:0] wdata;
output [DATASIZE - 1:0] rdata;
output wfull, rempty;
wire [ADDRSIZE - 1:0] waddr,raddr;
wire [ADDRSIZE:0] wptr, wrptr2, rptr, wrptr2;
sysc_r2w sysc_r2w(.wrptr2(wrptr2), .rptr(rptr), .wclock(wclock), .wreset(wreset));
syse_w2r syse_w2r(.rwptr2(rwptr2), .wptr(wptr), .rclock(rclock), .rreset(rreset));
fifomem fifomem(.rdata(rdata), .wdata(wdata), .waddr(waddr), .raddr(raddr), .wclock(wclock), .rclock(rclock), .wclken(winc), .rclken(rinc));
rptr_empty rptr_empty(.rempty(rempty), .raddr(raddr), .rptr(rptr), .rwptr2(rwptr2), .rinc(rinc), .rclock(rclock), .rreset(rreset));
wptr_full wptr_full(.wfull(wfull), .waddr(waddr), .wptr(wptr), .wrptr2(wrptr2), .winc(winc), .wclock(wclock), .wreset(wreset));
endmodule

The RTL circuit is shown in the figure: the
Insert picture description here
simulation result is shown in the figure below:
Insert picture description here

The instantiation process must be optimistic about the port interface,

Disclaimer: This article is only suitable for learning, and its content contains excerpts and summaries from the book. Welcome everyone to add and make progress together.

Guess you like

Origin blog.csdn.net/qq_24213087/article/details/108149182