写在前面的话:之前都是写了一些关于在实践中遇到的问题。今天在和同门讨论中发现都在用Verilog实现一些IP核的功能,感觉自己有点落后了,不高兴。所以就开始着手试着实现一下,一开始有点蒙,一直用RAM但是正道自己用verilog 实现的时候,就发现你的了解的特别透彻。才能来时现。开始正文。
RAM使我们经常用到的一个IP,在我们调用相关IP的时候就会发现RAM的种类还是挺多的。
第一步:认识RAM种类,并加以区别。
单端口RAM:对应IP核中的Single-Port RAM,只有一组控制信号线、地址线和数据线,不能同时读写,某时刻只能在控制信号作用下作为数据输入或输出的一种;
双端口RAM:对应IP核中的Dual-Port RAM,有两组独立的控制信号线、地址线和数据线,两组之间互不影响,允许两个独立的系统同时对其进行随机性的访问。即共享式多端口存储器,可以同时读写;
伪双端口RAM:对应IP核中的Simple Dual-Port RAM,一个端口只读,一个端口只写;
注意:双端口RAM同时对同一地址进行读写时,会出现仲裁;FIFO:先进先出数据缓冲器,也是一个端口只读,另一个端口只写。但是FIFO与伪双口RAM的不同,FIFO为先入先出,没有地址线,不能对存储单元寻址;而伪双口RAM两个端口都有地址线,可以对存储单元寻址。
第二步:RAM与FIFO的相关联系以及应用场合
如FIFO实现专题所述,FIFO既可以利用寄存器实现,也可以使用RAM实现;实际上,规模较大的FIFO一般都是用RAM实现的(规模特别小的FIFO才会使用寄存器实现)。FIFO常用于数据传输缓存,避免数据丢失,如跨时钟域的数据传输就需要用到异步FIFO。RAM常用于暂存指令或中间数据,指令cache和数据cache就由RAM来实现。
第三步:实现这些RAM
(1)单口RAM的实现:同步读,同步写
1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 // Project Name : 3 // Website : https://home.cnblogs.com/lgy-gdeu/ 4 // Author : LGY GUET Uiversity 5 // Weixin : li15226499835 6 // Email : 15277385992@163.com 7 // File : 8 // Create : 2020 9 // Revise : 10 // Editor : sublime text{SUBLIME_VERSION}, tab size ({TABS}) 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 // Modification History: 13 // Date By Version Change Description 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 // {DATE} {TIME} LGY 1.0 ++++++++++++++++ 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 module signle_port_synrdwr #( 19 parameter DATA_WIDTH = 8, 20 parameter ADDR_WIDTH = 4, 21 parameter DEEPTH = 2**ADDR_WIDTH 22 ) 23 ( 24 //system signals 25 input wire sclk , 26 input wire sp_sy_oe , 27 input wire sp_sy_wr , 28 input wire sp_sy_cs , 29 input wire [ADDR_WIDTH-1:0] spsy_addr , 30 inout wire [DATA_WIDTH-1:0] spsy_data 31 ); 32 33 //========================================================================\ 34 // ################ Define Parameter and Internal signals ################ 35 //========================================================================/ 36 reg [DATA_WIDTH-1:0] block_mem [0:DEEPTH-1] ; //相当于分配一个存储空间 37 reg [DATA_WIDTH-1:0] reg_spsy_data ; //中间寄存器 38 39 //============================================================================= 40 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 41 //============================================================================= 42 //initialalization 43 integer i ; 44 initial begin 45 for(i = 0 ; i< DEEPTH;i= i+1 )begin 46 block_mem[i] = 8'h0 ; 47 end 48 end 49 50 //out data 51 assign spsy_data = (sp_sy_cs & sp_sy_oe & !sp_sy_wr)? reg_spsy_data : 'hz; 52 53 54 //write port 55 always @(posedge sclk )begin 56 if(sp_sy_wr & sp_sy_cs ) 57 block_mem[spsy_addr] <= reg_spsy_data; 58 else 59 block_mem[spsy_addr] <= block_mem[spsy_addr]; 60 end 61 62 //read port 63 always @(posedge sclk )begin 64 if(sp_sy_cs & !sp_sy_wr & sp_sy_oe) 65 reg_spsy_data <= block_mem[spsy_addr]; 66 67 end 68 69 endmodule