当前位置:网站首页>FPGA skimming memory (Verilog implementation of ram and FIFO)
FPGA skimming memory (Verilog implementation of ram and FIFO)
2022-07-29 02:30:00 【Juanshi】
The problems in the memory part of Niuke network are RAM The implementation of the , I put FIFO The implementation of is also put together :


Catalog
Double port RAM The implementation of the
The generation and shooting of gray code
Single port RAM Realization

You can know from the conditions given in the title , The input end mainly contains data , Address and write enable three signals , about Single port RAM, Only one end has an address and an enable signal , Then the input data is valid and deposited when the enable is pulled up , Then the address changes from 0-127 change , Store input data , When outputting data, it is necessary to ensure that the input end does not write data , That is, lower the write enable .
In contrast to Dual port RAM, Dual port RAM There are enable signals at both ends of the read and write , Read enable is lowered when writing data , Write enable is lowered when reading data . And the addresses of the two ports are independent of each other .
The code flow is as follows :
(1) First, define the data register of the bit width and depth required by the topic , A wide = Writing data = Read data bit width , Depth according to the requirements of the topic , The format is :reg 【 A wide 】 name 【 depth 】;
(2) Under the reset signal , Assign an initial value to the data register 0, It's used here for sentence
Defining parameters integer i
for(i=0;i< depth ;i++)begin
name 【i】<=0;
end
(3) Enable signal =1 when , Store the write data into the data register
(4) Enable signal =0 when , Read data register data , Otherwise, do not read
module RAM_1port(
input clk,
input rst,
input enb,
input [6:0]addr,
input [3:0]w_data,
output wire [3:0]r_data
);
//*************code***********//
reg [3:0] data_temp[127:0];// Define the depth as 128 Of 4 Bit width data register
integer i;// Defining parameters i
[email protected](posedge clk or negedge rst)begin
if(~rst)begin
for(i=0;i<127;i++)begin
data_temp[i]<=0;// Clear the data register
end
end
else if(enb)begin// To make effective
data_temp[addr]<=w_data;// Save the data
end
end
assign r_data=(~enb)? data_temp[addr]:4'd0;// Write enable low level output , High level does not output
//*************code***********//
endmoduleDouble port RAM The implementation of the

First of all, we should realize RAM, First, declare the storage space of the data . After declaring the storage variable , Need to be right ram To initialize , Write data , When write_en It works , towards write_addr write in write_data, When read_en It works , According to the input read_addr Output read_data. It should be noted that , The topic requires the realization of true dual ports RAM, That is, it can be written and read at the same time , So you need to use two always The statement block implements write and read logic , Not in the same always Block the use of if-else if-else if result .
The code idea is as follows :
(1) First, define the data register of the bit width and depth required by the topic , A wide = Writing data = Read data bit width , Depth according to the requirements of the topic , The format is :reg 【 A wide 】 name 【 depth 】;
(2) Under the reset signal , Assign an initial value to the data register 0, It's used here for sentence
Defining parameters integer i
for(i=0;i< depth ;i++)begin
name 【i】<=0;
end
(3) Write enable signal =1 when , Store the write data into the data register
(4) Read enable signal =1 when , Read data register data , Otherwise, do not read
module ram_mod(
input clk,
input rst_n,
input write_en,
input [7:0]write_addr,
input [3:0]write_data,
input read_en,
input [7:0]read_addr,
output reg [3:0]read_data
);
reg[3:0] data_reg[7:0];// Define the bit width as 4 Depth is 8 Data register for
integer i;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
for(i=0;i<7;i++)begin
data_reg[i]<=0;
end
end
else if(write_en)begin
data_reg[write_addr]<=write_data;// Write
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
read_data<=4'd0;
end
else if(read_en)begin
read_data<=data_reg[read_addr];// read
end
else begin
read_data<=4'd0;
end
end
endmoduleSync FIFO Realization

FIFO The implementation of depends on two ports RAM, Here's the picture ,RAM The enablers and data of can be compared with FIFO Direct connection , Need to generate RAM Write address and read address , But also produce full full And read empty empty The signal ( Lower right icon red ):

Generate read and write addresses :
waddr Write the address +1 The situation of : To make effective && It's not full
raddr Read the address +1 The situation of : Reading enables effective && No time to read
assign wenc = winc && !wfull; // Write the address +
assign renc = rinc && !rempty;// Read the address +
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
waddr <= 'd0;
else if (wenc)
waddr <= waddr + 'd1;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
raddr <= 'd0;
else if (renc)
raddr <= raddr + 'd1;
endGenerate empty full signal :
wfull Write full : Read the address == Write the address + depth
rempty Reading empty : Read the address == Write the address
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wfull <= 'd0;
rempty <= 'd0;
end
else begin
wfull <= waddr == raddr + DEPTH;
rempty <= waddr == raddr;
end
endasynchronous FIFO Realization

asynchronous FIFO It is the focus of the written interview of major companies . The difficulty is still the empty and full signal . asynchronous FIFO And synchronization FIFO The core difference is that its read clock and write clock are not synchronized . So when using the method of comparing read and write addresses to generate empty and full signals , Cross clock domain processing is required . In order to reduce the possibility of metastable state , asynchronous FIFO Gray code is also introduced . meanwhile , Gray code is also more convenient to generate empty and full signals .
The figure above shows this asynchronous FIFO The structure of . The blue area is the reading clock field , The yellow part is the write clock field . asynchronous FIFO It mainly includes four parts : Read write address generator 、 The generation and shooting of gray code 、 Empty / full signal generator and RAM. This question has been given RAM part .
Read write address generator
produce FIFO Natural binary read and write address . When reading enable rinc==1 And FIFO Non empty rempty==0 when , Reading address is reading clock rclk Downward self increasing ; When write enable winc==1 And FIFO Not full wfull==0 when , Writing address is writing clock wclk Downward self increasing . These two addresses can be passed in directly RAM modular .
wire wenc, renc;
wire [$clog2(DEPTH)-1:0] waddr, raddr;
assign wenc = winc&!wfull;
assign renc = rinc&!rempty;
[email protected](posedge wclk or negedge wrstn) begin
if(~wrstn)
waddr_bin <= 0;
else
waddr_bin <= wenc? waddr_bin+1: waddr_bin;
end
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn)
raddr_bin <= 0;
else
raddr_bin <= renc? raddr_bin+1: raddr_bin;
end
The generation and shooting of gray code
In order to generate an empty full signal , You need to compare the size of the read-write address . But the two addresses are controlled by different clocks , Cross clock domain processing is required before comparison . So I used two shots . Again because FIFO The read-write address of is continuously changing , Using gray code can effectively reduce the number of adjacent addresses bit change , Further reduce the possibility of metastable state in the beating process .
Last , Natural binary address and gray code address are $clog2(DEPTH)+1bit, Than waddr and raddr More 1bit. The bit It is used to assist in generating full signal .
reg [$clog2(DEPTH):0] waddr_bin, raddr_bin;
wire [$clog2(DEPTH):0] waddr_gray, raddr_gray;
reg [$clog2(DEPTH):0] waddr_gray1, raddr_gray1;
reg [$clog2(DEPTH):0] waddr_gray2, raddr_gray2;
reg [$clog2(DEPTH):0] waddr_gray3, raddr_gray3;
assign waddr_gray = waddr_bin^(waddr_bin>>1);
assign raddr_gray = raddr_bin^(raddr_bin>>1);
assign waddr = waddr_bin[$clog2(DEPTH)-1:0];
assign raddr = raddr_bin[$clog2(DEPTH)-1:0];
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn)
raddr_gray1 <= 0;
else
raddr_gray1 <= raddr_gray;
end
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn) begin
waddr_gray2 <= 0;
waddr_gray3 <= 0;
end
else begin
waddr_gray2 <= waddr_gray1;
waddr_gray3 <= waddr_gray2;
end
end
[email protected](posedge wclk or negedge wrstn) begin
if(~wrstn) begin
raddr_gray2 <= 0;
raddr_gray3 <= 0;
end
else begin
raddr_gray2 <= raddr_gray1;
raddr_gray3 <= raddr_gray2;
end
end
When counting with natural binary code , There may be many... Between adjacent data bit The change of . This will cause large peak currents and other problems . Gray code is a kind of adjacent data only 1bit Changing code system .
| Decimal system | Natural binary | Gray code |
|---|---|---|
| 0 | 000 | 000 |
| 1 | 001 | 001 |
| 2 | 010 | 011 |
| 3 | 011 | 010 |
| 4 | 100 | 110 |
| 5 | 101 | 111 |
| 6 | 110 | 101 |
| 7 | 111 | 100 |

Empty / full signal generator
When the gray code of read and write address is only the highest 2bit Different time ,FIFO full ; When the read and write addresses are exactly the same ,FIFO empty .
assign wfull = (waddr_gray1=={~raddr_gray3[$clog2(DEPTH):$clog2(DEPTH)-1], raddr_gray3[$clog2(DEPTH)-2:0]});
assign rempty = (raddr_gray1==waddr_gray3);
asynchronous FIFO Complete code :
`timescale 1ns/1ns
/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr // Depth pair 2 Take the logarithm , Get the bit width of the address .
,input [WIDTH-1:0] wdata // Data writing
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr // Depth pair 2 Take the logarithm , Get the bit width of the address .
,output reg [WIDTH-1:0] rdata // Data output
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/***************************************AFIFO*****************************************/
module asyn_fifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input wclk ,
input rclk ,
input wrstn ,
input rrstn ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output wire wfull ,
output wire rempty ,
output wire [WIDTH-1:0] rdata
);
wire [$clog2(DEPTH)-1:0] waddr, raddr;
reg [$clog2(DEPTH) :0] waddr_bin, raddr_bin;
wire [$clog2(DEPTH) :0] waddr_gray, raddr_gray;
reg [$clog2(DEPTH) :0] waddr_gray1, raddr_gray1;
reg [$clog2(DEPTH) :0] waddr_gray2, raddr_gray2;
reg [$clog2(DEPTH) :0] waddr_gray3, raddr_gray3;
wire wenc, renc;
[email protected](posedge wclk or negedge wrstn) begin
if(~wrstn)
waddr_bin <= 0;
else
waddr_bin <= wenc? waddr_bin+1: waddr_bin;
end
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn)
raddr_bin <= 0;
else
raddr_bin <= renc? raddr_bin+1: raddr_bin;
end
[email protected](posedge wclk or negedge wrstn) begin
if(~wrstn)
waddr_gray1 <= 0;
else
waddr_gray1 <= waddr_gray;
end
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn)
raddr_gray1 <= 0;
else
raddr_gray1 <= raddr_gray;
end
[email protected](posedge rclk or negedge rrstn) begin
if(~rrstn) begin
waddr_gray2 <= 0;
waddr_gray3 <= 0;
end
else begin
waddr_gray2 <= waddr_gray1;
waddr_gray3 <= waddr_gray2;
end
end
[email protected](posedge wclk or negedge wrstn) begin
if(~wrstn) begin
raddr_gray2 <= 0;
raddr_gray3 <= 0;
end
else begin
raddr_gray2 <= raddr_gray1;
raddr_gray3 <= raddr_gray2;
end
end
assign waddr_gray = waddr_bin^(waddr_bin>>1);
assign raddr_gray = raddr_bin^(raddr_bin>>1);
assign waddr = waddr_bin[$clog2(DEPTH)-1:0];
assign raddr = raddr_bin[$clog2(DEPTH)-1:0];
assign wenc = winc&!wfull;
assign renc = rinc&!rempty;
assign wfull = (waddr_gray1=={~raddr_gray3[$clog2(DEPTH):$clog2(DEPTH)-1], raddr_gray3[$clog2(DEPTH)-2:0]});
assign rempty = (raddr_gray1==waddr_gray3);
dual_port_RAM #(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
myRAM(
.wclk (wclk ),
.wenc (wenc ),
.waddr(waddr),
.wdata(wdata),
.rclk (rclk ),
.renc (renc ),
.raddr(raddr),
.rdata(rdata)
);
endmodule
边栏推荐
- 2022/07/28 学习笔记 (day18) 常用API
- How to quickly design a set of cross end components that support rendering rich text content
- HTTP缓存
- Responsive dream weaving template hotel room website
- 7/28 高斯消元解线性方程组+高斯消元解异或线性方程组 +求组合数ii
- The outsourcing company "mixed" for two years, and I only did five things seriously. Now I get byte offer smoothly.
- Meeting notice of meeting OA
- Awvs cannot start problem
- 详解异步任务:任务的状态及生命周期管理
- 数据安全与隐私计算峰会-安全求交集在隐私计算中的发展和应用:学习
猜你喜欢

Esbuild Bundler HMR

Object based real-time spatial audio rendering - Dev for dev column

如果非要在多线程中使用 ArrayList 会发生什么?

The outsourcing company "mixed" for two years, and I only did five things seriously. Now I get byte offer smoothly.

如何利用 RPA 实现自动化获客?

How to quickly design a set of cross end components that support rendering rich text content

NPM install reports an error: eperm: operation not permitted, rename

Keil5 open the engineering prompt not found device solution

无线振弦采集系统工作流程

我被这个浏览了 746000 次的问题惊住了
随机推荐
[RT learning note 1] RT thread peripheral routine - control LED light flashing
响应式织梦模板户外露营类网站
I want to talk about high concurrency.
Object based real-time spatial audio rendering - Dev for dev column
一文搞懂 Redis 架构演化之路
聊聊接口性能优化的11个小技巧
响应式织梦模板化妆美妆类网站
3d智能工厂工艺流转可视化交互展示应用优点
一文理解分布式开发中的服务治理
QT qstackedwidget multi interface switching
TCP重传机制有哪些?
npm install 报错 Error: EPERM: operation not permitted, rename
工程经济学简答题
Awvs cannot start problem
响应式织梦模板酒店客房类网站
Virsh console connection failure
Responsive dream weaving template home decoration building materials website
3D模型格式全解|含RVT、3DS、DWG、FBX、IFC、OSGB、OBJ等70余种
Esbuild Bundler HMR
详解JS的四种异步解决方案:回调函数、Promise、Generator、async/await