写在前面的话:之前都是写了一些关于在实践中遇到的问题。今天在和同门讨论中发现都在用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
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 19 module tb_single_port_synrdwr(); 20 21 22 parameter DATA_WIDTH = 8; 23 parameter ADDR_WIDTH = 4; 24 parameter DEEPTH = 2**ADDR_WIDTH; 25 26 reg sclk ; 27 reg sp_sy_oe ; 28 reg sp_sy_wr ; 29 reg sp_sy_cs ; 30 reg [ADDR_WIDTH-1:0] spsy_addr ; 31 wire [DATA_WIDTH-1:0] spsy_data ; 32 33 34 //========================================================================\ 35 // ################ Define Parameter and Internal signals ################ 36 //========================================================================/ 37 reg [DATA_WIDTH-1:0] reg_spsy_data ; 38 39 assign spsy_data = (sp_sy_cs & sp_sy_wr & !sp_sy_oe ) ? reg_spsy_data : 'hz ; 40 41 42 //============================================================================= 43 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 44 //============================================================================= 45 46 //first generate sclk 47 initial begin 48 sclk = 0; 49 forever 50 #5 sclk = ~sclk ; 51 end 52 53 //second generate tiaojian 54 55 initial begin 56 sp_sy_cs = 1'b0 ; 57 sp_sy_wr = 1'b0 ; 58 sp_sy_oe = 1'b0 ; 59 spsy_addr = 4'b000; 60 reg_spsy_data = 8'd0; 61 #20 62 @(negedge sclk)begin //read 63 sp_sy_oe = 1'b1 ; 64 sp_sy_cs = 1'b1 ; 65 end 66 repeat(15) #20 spsy_addr = spsy_addr + 1 ; 67 68 #40 69 @(negedge sclk)begin //write 70 sp_sy_cs = 1'b1 ; 71 sp_sy_wr = 1'b1 ; 72 end 73 repeat(15) #20 begin 74 spsy_addr = spsy_addr + 1 ; 75 reg_spsy_data = reg_spsy_data + 1; 76 end 77 78 #40 79 @(negedge sclk )begin 80 sp_sy_oe = 1; 81 sp_sy_cs = 1; 82 end 83 repeat(15) #20begin 84 spsy_addr = spsy_addr + 1'b1 ; 85 end 86 87 88 @(negedge sclk) 89 sp_sy_cs = 0; 90 #40 91 $stop ; 92 93 end 94 95 //lihua mon=ban 96 signle_port_synrdwr #( 97 .DATA_WIDTH(DATA_WIDTH), 98 .ADDR_WIDTH(ADDR_WIDTH), 99 .DEEPTH(DEEPTH) 100 ) inst_signle_port_synrdwr ( 101 .sclk (sclk), 102 .sp_sy_oe (sp_sy_oe), 103 .sp_sy_wr (sp_sy_wr), 104 .sp_sy_cs (sp_sy_cs), 105 .spsy_addr (spsy_addr), 106 .spsy_data (spsy_data) 107 ); 108 109 110 111 112 113 114 endmodule
在实现的时候其实,并不是太难,关键是要注意测试文件的写法。所谓的同步是时钟同步并不是读写同时。这一点要弄清楚,还有测试激励中的repeat 的使用方法,注意只能在激励中使用,如果使用在行为电路中的话综合不成电路。
(2)单口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-6-16 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 single_port_asyrdwr #( 19 parameter ADDR_WIDTH = 4 , 20 parameter DATA_WIDTH = 8 , 21 parameter DEEPTH = ADDR_WIDTH << 1 22 ) 23 ( 24 //system signals 25 input wire asy_spram_cs , 26 input wire asy_spram_wr , 27 input wire asy_spram_oe , 28 input wire [ADDR_WIDTH-1:0] asy_spram_addr , 29 inout wire [DATA_WIDTH-1:0] asy_spram_data 30 31 32 ); 33 34 //========================================================================\ 35 // ################ Define Parameter and Internal signals ################ 36 //========================================================================/ 37 reg [DATA_WIDTH-1:0] block_mem [0:DEEPTH-1] ; //相当于是给一个存储空间 38 reg [DATA_WIDTH-1:0] reg_asy_spram_data ; //数据的中间变量 39 40 //============================================================================= 41 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 42 //============================================================================= 43 //initiallization 44 integer i ; 45 initial begin 46 for (i = 0; i <= DEEPTH-1; i = i + 1) 47 begin 48 block_mem[i] = 8'h00; 49 end 50 51 end 52 53 //wr_port 54 always @(*) begin 55 if(asy_spram_wr & asy_spram_cs)begin 56 block_mem[asy_spram_addr] = asy_spram_data; 57 end 58 else begin 59 block_mem[asy_spram_addr] = block_mem[asy_spram_addr]; 60 end 61 end 62 63 //rd_port 64 65 always @( * )begin 66 if(asy_spram_cs & !asy_spram_wr & asy_spram_oe)begin 67 reg_asy_spram_data = block_mem[reg_asy_spram_data]; 68 end 69 end 70 71 //out data 72 assign asy_spram_data = (asy_spram_cs & !asy_spram_wr & asy_spram_oe)?reg_asy_spram_data:{DATA_WIDTH{1'bz}}; 73 74 75 endmodule
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 tb_single_port_asyrdwr(); 19 20 21 //========================================================================\ 22 // ################ Define Parameter and Internal signals ################ 23 //========================================================================/ 24 25 parameter ADDR_WIDTH = 4 ; 26 parameter DATA_WIDTH = 8 ; 27 parameter DEEPTH = ADDR_WIDTH << 1 ; 28 29 reg asy_spram_cs ; 30 reg asy_spram_wr ; 31 reg asy_spram_oe ; 32 reg [ADDR_WIDTH-1:0] asy_spram_addr ; 33 wire [DATA_WIDTH-1:0] asy_spram_data ; 34 35 reg [DATA_WIDTH-1:0] reg_asy_spram_data; 36 reg sclk ; 37 38 //============================================================================= 39 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 40 //============================================================================= 41 42 initial begin 43 sclk = 0; 44 forever #10 begin 45 sclk = ~sclk ; 46 end 47 end 48 49 assign asy_spram_data = (asy_spram_cs & asy_spram_wr )?reg_asy_spram_data:8'bzzzz_zzzz; 50 51 52 initial begin 53 asy_spram_cs = 1'b1 ; 54 asy_spram_oe = 1'b1 ; 55 asy_spram_wr = 1'b0 ; 56 asy_spram_addr = 4'b0000; 57 reg_asy_spram_data = 8'd1; 58 #20//read 59 repeat(15) #20 begin 60 asy_spram_addr = asy_spram_addr + 1; 61 end 62 #20//write 63 asy_spram_wr = 1'b1 ; 64 repeat(15) begin 65 #20 66 asy_spram_addr = asy_spram_addr+ 1; 67 reg_asy_spram_data = reg_asy_spram_data + 1 ; 68 end 69 #20//读 70 asy_spram_wr = 1'b0 ; 71 repeat(15) begin 72 #20 73 asy_spram_addr = asy_spram_addr + 1; 74 end 75 76 77 end 78 79 80 81 single_port_asyrdwr #( 82 .ADDR_WIDTH(ADDR_WIDTH), 83 .DATA_WIDTH(DATA_WIDTH), 84 .DEEPTH(DEEPTH) 85 ) inst_single_port_asyrdwr ( 86 .asy_spram_cs (asy_spram_cs), 87 .asy_spram_wr (asy_spram_wr), 88 .asy_spram_oe (asy_spram_oe), 89 .asy_spram_addr (asy_spram_addr), 90 .asy_spram_data (asy_spram_data) 91 ); 92 93 94 endmodule
(3)双口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-06-16 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 double_port_synrdwr_ram #( 19 parameter ADDR_WIDTH = 4, 20 parameter DATA_WIDTH = 8, 21 parameter DEEPTH = 2**ADDR_WIDTH 22 ) 23 ( 24 //system signals 25 input wire sclk , 26 27 input wire port1_wr , 28 input wire port1_oe , 29 input wire port1_cs , 30 input wire [ADDR_WIDTH-1:0] port1_addr , 31 inout wire [DATA_WIDTH-1:0] port1_data , 32 33 input wire port2_wr , 34 input wire port2_oe , 35 input wire port2_cs , 36 input wire [ADDR_WIDTH-1:0] port2_addr , 37 inout wire [DATA_WIDTH-1:0] port2_data 38 39 ); 40 //========================================================================\ 41 // ################ Define Parameter and Internal signals ################ 42 //========================================================================/ 43 reg [DATA_WIDTH-1:0] block_mem [0:DEEPTH-1] ; 44 reg [DATA_WIDTH-1:0] reg_port1 ; 45 reg [DATA_WIDTH-1:0] reg_port2 ; 46 47 //============================================================================= 48 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 49 //============================================================================= 50 //initiallization 51 //block_mem 52 integer i; 53 initial begin 54 55 for (i = 0; i <=DEEPTH-1 ; i = i + 1) 56 begin 57 block_mem[i] = 8'h00; 58 end 59 end 60 61 //write path 62 //port1 write 63 always @(posedge sclk)begin 64 if(port1_cs & port1_wr)begin 65 block_mem[port1_addr] <= port1_data ; 66 end 67 // else begin 68 // block_mem[port1_addr] <= block_mem[port1_addr]; 69 // end 70 end 71 //port2 write 72 always @(posedge sclk)begin 73 if(port2_wr & port2_cs)begin 74 block_mem[port2_addr] <= port2_data ; 75 end 76 // else begin 77 // block_mem[port2_addr] <= block_mem[port2_addr]; 78 // end 79 end 80 81 82 //read path 83 //port1_read 84 always @(posedge sclk )begin 85 if(port1_cs & port1_oe & !port1_wr)begin 86 reg_port1 <= block_mem[port1_addr]; 87 end 88 // else begin 89 // reg_port1 <= reg_port1 ; 90 // end 91 end 92 93 //port2_read 94 always @(posedge sclk)begin 95 if(port2_cs & port2_oe & !port2_wr)begin 96 reg_port2 <= block_mem[port2_addr]; 97 end 98 // else begin 99 // reg_port2 <= reg_port2 ; 100 // end 101 102 end 103 104 //out 105 assign port1_data = (port1_cs & port1_oe & !port1_wr)? reg_port1:{DATA_WIDTH{1'bz}}; 106 assign port2_data = (port2_cs & port2_oe & !port2_wr)? reg_port2:{DATA_WIDTH{1'bz}}; 107 endmodule
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-06-16 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 tb_double_port_synrdwr_ram(); 19 20 parameter ADDR_WIDTH = 4 ; 21 parameter DATA_WIDTH = 8 ; 22 parameter DEEPTH = ADDR_WIDTH<<1 ; 23 24 reg sclk ; 25 reg port1_wr ; 26 reg port1_oe ; 27 reg port1_cs ; 28 reg [ADDR_WIDTH-1:0] port1_addr ; 29 wire [DATA_WIDTH-1:0] port1_data ; 30 reg port2_wr ; 31 reg port2_oe ; 32 reg port2_cs ; 33 reg [ADDR_WIDTH-1:0] port2_addr ; 34 wire [DATA_WIDTH-1:0] port2_data ; 35 36 //========================================================================\ 37 // ################ Define Parameter and Internal signals ################ 38 //========================================================================/ 39 40 reg [DATA_WIDTH-1:0] reg_port1; 41 reg [DATA_WIDTH-1:0] reg_port2; 42 43 assign port1_data = (port1_cs & !port1_oe & port1_wr)? reg_port1:{DATA_WIDTH{1'bz}}; 44 assign port2_data = (port2_cs & !port2_oe & port2_wr)? reg_port2:{DATA_WIDTH{1'bz}}; 45 46 47 //generate clock 48 initial begin 49 sclk = 0; 50 forever begin 51 #10 sclk = ~sclk ; 52 end 53 end 54 55 //start read&write 56 initial begin 57 #100 58 port1_wr = 0 ; 59 port1_oe = 0 ; 60 port1_cs = 0 ; 61 port1_addr = 4'b0000; 62 reg_port1 = 8'd0; 63 port2_oe = 0; 64 port2_cs = 0; 65 port2_wr = 0; 66 port2_addr = 4'b1111; 67 reg_port2 = 8'd0; 68 //同步读,port1读0-15,port2 读15-0 69 @(posedge sclk)begin 70 port1_wr = 0 ; 71 port1_oe = 1 ; 72 port1_cs = 1 ; 73 port2_oe = 1; 74 port2_cs = 1; 75 port2_wr = 0; 76 end 77 repeat(15) begin 78 #20 79 port1_addr = port1_addr + 1; 80 port2_addr = port2_addr - 1; 81 end 82 83 //设置port1读15-0,port2写0-15 84 @(posedge sclk )begin 85 port1_wr = 0 ; 86 port1_oe = 1 ; 87 port1_cs = 1 ; 88 port2_oe = 0; 89 port2_cs = 1; 90 port2_wr = 1; 91 end 92 repeat(15)begin 93 #20 94 port1_addr = port1_addr - 1; 95 port2_addr = port2_addr + 1; 96 reg_port2 = reg_port2 + 1; 97 end 98 //设置同步写0-15 99 @(posedge sclk) begin 100 port1_wr = 1 ; 101 port1_oe = 0 ; 102 port1_cs = 1 ; 103 port2_oe = 0; 104 port2_cs = 1; 105 port2_wr = 1; 106 port2_addr = 4'b0000; 107 port1_addr = 4'b0000; 108 reg_port2 = 0; 109 reg_port1 = 0; 110 end 111 repeat(15) begin 112 #20 113 port1_addr = port1_addr + 1; 114 port2_addr = port2_addr + 1; 115 reg_port1 = reg_port1+1; 116 reg_port2 = reg_port2+1; 117 end 118 end 119 120 121 //inst 122 double_port_synrdwr_ram #( 123 .ADDR_WIDTH(ADDR_WIDTH), 124 .DATA_WIDTH(DATA_WIDTH), 125 .DEEPTH(DEEPTH) 126 ) inst_double_port_synrdwr_ram ( 127 .sclk (sclk), 128 .port1_wr (port1_wr), 129 .port1_oe (port1_oe), 130 .port1_cs (port1_cs), 131 .port1_addr (port1_addr), 132 .port1_data (port1_data), 133 .port2_wr (port2_wr), 134 .port2_oe (port2_oe), 135 .port2_cs (port2_cs), 136 .port2_addr (port2_addr), 137 .port2_data (port2_data) 138 ); 139 140 141 142 143 144 endmodule
(4)双口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 double_port_asyrdwr_ram #( 19 parameter ADDR_WIDTH = 4 , 20 parameter DATA_WIDTH = 8 , 21 parameter DEEPTH = 1<<ADDR_WIDTH 22 ) 23 ( 24 //system signals 25 input wire sclk1 , 26 input wire port1_wr , 27 input wire port1_cs , 28 input wire port1_oe , 29 input wire [ADDR_WIDTH-1:0] port1_addr , 30 inout wire [DATA_WIDTH-1:0] port1_data , 31 32 input wire sclk2 , 33 input wire port2_wr , 34 input wire port2_cs , 35 input wire port2_oe , 36 input wire [ADDR_WIDTH-1:0] port2_addr , 37 inout wire [DATA_WIDTH-1:0] port2_data 38 39 40 ); 41 42 //========================================================================\ 43 // ################ Define Parameter and Internal signals ################ 44 //========================================================================/ 45 reg [DATA_WIDTH-1:0] block_mem [0:DEEPTH-1] ; 46 reg [DATA_WIDTH-1:0] reg_port1 ; 47 reg [DATA_WIDTH-1:0] reg_port2 ; 48 49 //============================================================================= 50 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 51 //============================================================================= 52 //initiallization 53 integer i ; 54 initial begin 55 for (i = 0; i <= DEEPTH-1; i = i + 1) 56 begin 57 block_mem[i] = 8'h00; 58 end 59 end 60 61 //write path 62 always @(posedge sclk1)begin 63 if(port1_cs & port1_wr)begin 64 block_mem[port2_addr] <= port2_data; 65 end 66 end 67 68 always @(posedge sclk2)begin 69 if(port2_cs & port2_wr)begin 70 block_mem[port2_addr] <= port2_data; 71 end 72 end 73 74 //read path 75 always @(posedge sclk1)begin 76 if(port1_oe & port2_cs & !port1_wr)begin 77 reg_port1 <= block_mem[port1_addr]; 78 end 79 end 80 81 always @(posedge sclk2)begin 82 if(port2_cs & port2_oe & !port2_wr)begin 83 reg_port2 <= block_mem[port2_addr]; 84 end 85 end 86 87 //out data 88 assign port1_data = (port1_cs & port1_oe & !port1_wr)?reg_port1:{DATA_WIDTH{1'bz}}; 89 assign port2_data = (port2_cs & port2_oe & !port2_wr)?reg_port2:{DATA_WIDTH{1'bz}}; 90 91 endmodule
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 tb_double_port_asyrdwr_ram(); 19 20 parameter ADDR_WIDTH = 4 ; 21 parameter DATA_WIDTH = 8 ; 22 parameter DEEPTH = 1<<ADDR_WIDTH; 23 24 reg sclk1 ; 25 reg port1_wr ; 26 reg port1_cs ; 27 reg port1_oe ; 28 reg [ADDR_WIDTH-1:0] port1_addr ; 29 wire [DATA_WIDTH-1:0] port1_data ; 30 reg sclk2 ; 31 reg port2_wr ; 32 reg port2_cs ; 33 reg port2_oe ; 34 reg [ADDR_WIDTH-1:0] port2_addr ; 35 wire [DATA_WIDTH-1:0] port2_data ; 36 //========================================================================\ 37 // ################ Define Parameter and Internal signals ################ 38 //========================================================================/ 39 40 reg [DATA_WIDTH-1:0] reg_port1 ; 41 reg [DATA_WIDTH-1:0] reg_port2 ; 42 43 assign port1_data = (port1_cs & port1_wr)? reg_port1 : {DATA_WIDTH{1'bz}}; 44 assign port2_data = (port2_cs & port2_wr)? reg_port2 : {DATA_WIDTH{1'bz}}; 45 46 47 initial begin 48 sclk1 = 0; 49 forever #10 sclk1 = ~sclk1 ; 50 end 51 52 53 initial begin 54 sclk2 = 0; 55 forever #25 sclk2 = ~sclk2 ; 56 end 57 58 initial begin 59 fork begin 60 61 port1_addr = 4'b0000; 62 reg_port1 = 8'd0; 63 port1_wr = 1'b1; 64 port1_oe = 1'b0; 65 port1_cs = 1'b1; 66 repeat(15) begin//port1写1-15于地址0-15 67 #20 port1_addr = port1_addr+1'b1; 68 reg_port1 = reg_port1+1'b1; 69 end 70 end 71 begin 72 73 port2_addr = 4'b0000; 74 reg_port2 = 8'd0; 75 port2_wr = 1'b0; 76 port2_oe = 1'b1; 77 port2_cs = 1'b1; 78 repeat(15) begin//port2读地址0-15 79 #40 port2_addr = port2_addr+1'b1; 80 end 81 end 82 join 83 84 #40 85 fork begin 86 port1_wr = 1'b0; 87 port1_oe = 1'b1; 88 port1_cs = 1'b1; 89 repeat(15) begin//port1读于地址15-0 90 #20 port1_addr = port1_addr-1'b1; 91 end 92 end 93 begin 94 reg_port2 = 8'b1111_1111; 95 port2_wr = 1'b1; 96 port2_oe = 1'b0; 97 port2_cs = 1'b1; 98 repeat(15) begin//port2写11111111于地址15-0 99 #40 port2_addr = port2_addr-1'b1; 100 end 101 end 102 join 103 end 104 105 106 double_port_asyrdwr_ram #( 107 .ADDR_WIDTH(ADDR_WIDTH), 108 .DATA_WIDTH(DATA_WIDTH), 109 .DEEPTH(DEEPTH) 110 ) inst_double_port_asyrdwr_ram ( 111 .sclk1 (sclk1), 112 .port1_wr (port1_wr), 113 .port1_cs (port1_cs), 114 .port1_oe (port1_oe), 115 .port1_addr (port1_addr), 116 .port1_data (port1_data), 117 .sclk2 (sclk2), 118 .port2_wr (port2_wr), 119 .port2_cs (port2_cs), 120 .port2_oe (port2_oe), 121 .port2_addr (port2_addr), 122 .port2_data (port2_data) 123 ); 124 125 126 endmodule
总结:这里没有对代码和时序图的具体分析。关于实现的过程主要要有一个大概的输入输出框图。
单口的RAM:记住下面的框图,和接口的走向,剩下的了解逻辑就可以写出来了。注意:DATA的数据类型。
伪双口RAM:
双口RAM:
实际应用注意:
(1)无论是简单双口RAM还是真双口RAM,在没有读操作的情况下,应将读使能rden信号拉成低电平,节省功耗。
(2)在两种情况下,都应当避免read-during-write,虽然可在软件中进行设置,但是,作为设计者,应当尽量避免此种情况。
(3)对于真双口RAM,还应当避免两个读端口或者两个写端口同时操作同一个地址,RAM中并没有此种冲突解决电路,设计者应该避免这种冲突。