一、项目要求
1、用两个伪双端口的RAM实现缓存
2、先写buffer1,再写buffer2 ,在读buffer1的同时写buffer2,在读buffer2的同时写buffer1。
3、写端口50M时钟,写入16个8bit 的数据,读出时钟25M,读出8个16bit 的数据。
二、信号转换图:
三、状态转换图:
四、程序设计:
先配置IP:
`timescale 1ns / 1ps
module ping_pang_1(
input sys_clk ,
input rst_n ,
output wire [15 : 0] doutb1 ,
output wire [15 : 0] doutb2
);
wire clk_50M ;
wire clk_25M ;
wire locked ;
wire en ;
assign en = locked & rst_n;
clk_wiz_0 instance_name
(
// Clock out ports
.clk_50M(clk_50M), // output clk_out1
.clk_25M(clk_25M), // output clk_out2
// Status and control signals
.resetn(rst_n), // input resetn
.locked(locked), // output locked
// Clock in ports
.sys_clk(sys_clk)); // input clk_in1
ram1
reg wea1 ;
reg [3 : 0] addra1 ;
reg [7 : 0] dina1 ;
reg enb1 ;
reg [2 : 0] addrb1 ;
ping_pang ram1 (
.clka(clk_50M), // input wire clka
.ena(1), // input wire ena
.wea(wea1), // input wire [0 : 0] wea
.addra(addra1), // input wire [3 : 0] addra
.dina(dina1), // input wire [7 : 0] dina
.clkb(clk_25M), // input wire clkb
.enb(enb1), // input wire enb
.addrb(addrb1), // input wire [2 : 0] addrb
.doutb(doutb1) // output wire [15 : 0] doutb
);
ram2
reg wea2 ;
reg [3 : 0] addra2 ;
reg [7 : 0] dina2 ;
reg enb2 ;
reg [2 : 0] addrb2 ;
ping_pang ram2 (
.clka(clk_50M), // input wire clka
.ena(1), // input wire ena
.wea(wea2), // input wire [0 : 0] wea
.addra(addra2), // input wire [3 : 0] addra
.dina(dina2), // input wire [7 : 0] dina
.clkb(clk_25M), // input wire clkb
.enb(enb2), // input wire enb
.addrb(addrb2), // input wire [2 : 0] addrb
.doutb(doutb2) // output wire [15 : 0] doutb
);
/状态机
localparam IDLE = 3'd0;
localparam W1 = 3'd1;
localparam W2_R1 = 3'd2;
localparam W1_R2 = 3'd3;
reg [2:0] cur_state,next_state;
always@(posedge clk_50M)
if(!rst_n)
cur_state <= IDLE;
else if(en)
cur_state <= next_state;
else
cur_state <= IDLE;
always@(*)
case(cur_state)
IDLE :begin
next_state = W1;
end
W1 :begin
if(addra1 == 14 && wea1)
next_state = W2_R1;
else
next_state = cur_state;
end
W2_R1 :begin
if(addra2 == 14 && wea2)
next_state = W1_R2;
else
next_state = cur_state;
end
W1_R2 :begin
if(addra1 == 14 && wea1)
next_state = W2_R1;
else
next_state = cur_state;
end
default:;
endcase
/写状态机
always@(posedge clk_50M)
if(!rst_n)begin
wea1 <= 0;
addra1 <= 0;
dina1 <= 0;
wea2 <= 0;
addra2 <= 0;
dina2 <= 0;
end
else
case(cur_state)
IDLE :begin
end
W1 :begin
if(addra1 == 15)
wea1 <= 0;
else
wea1 <= 1;
if(wea1 == 1)
dina1 <= dina1 + 8'h27 ;
else
dina1 <= 0;
if(wea1 == 1 && addra1 == 15)
addra1 <= 0;
else if(wea1 == 1)
addra1 <= addra1 + 1;
else
addra1 <= addra1;
end
W2_R1:begin
addra1 <= 0;
wea1 <= 0; /ram1的写使能关闭
if(addra2 == 15)
wea2 <= 0;
else
wea2 <= 1;
if(wea2 == 1)
dina2 <= dina2 + 8'h19 ;
else
dina2 <= 0;
if(wea2 == 1 && addra2 == 15)
addra2 <= 0;
else if(wea2 == 1)
addra2 <= addra2 + 1;
else
addra2 <= 0;
end
W1_R2:begin
wea2 <= 0;
addra2 <= 0;
if(addra1 == 15)
wea1 <= 0;
else
wea1 <= 1;
if(wea1 == 1)
dina1 <= dina1 + 8'h27 ;
else
dina1 <= 0;
if(wea1 == 1 && addra1 == 15)
addra1 <= 0;
else if(wea1 == 1)
addra1 <= addra1 + 1;
else
addra1 <= 0;
end
default:;
endcase
读状态机
always@(negedge clk_25M)
if(!rst_n)begin
enb1 <= 0;
addrb1 <= 0;
enb2 <= 0;
addrb2 <= 0;
end
else
case(cur_state)
IDLE :begin
end
W1 :begin
end
W2_R1 :begin
enb2 <= 0;
addrb2 <= 0;
if(addrb1 == 7 && enb1)
enb1 <= 0;
else
enb1 <= 1;
if(enb1 == 1 && addrb1 == 7)
addrb1 <= 0;
else if(enb1)
addrb1 <= addrb1 + 1;
else
addrb1 <= 0;
end
W1_R2 :begin
addrb1 <= 0;
enb1 <= 0;
if(addrb2 == 7)
enb2 <= 0;
else
enb2 <= 1;
if(enb2 == 1 && addrb2 == 7)
addrb2 <= 0;
else if(enb2)
addrb2 <= addrb2 + 1;
else
addrb2 <= 0;
end
default:;
endcase
endmodule
五、仿真设计
`timescale 1ns / 1ps
module test_ping_pang( );
reg sys_clk ;
reg rst_n ;
wire[15:0] doutb1 ;
wire[15:0] doutb2 ;
initial
begin
sys_clk = 0 ;
rst_n = 0 ;
#10
rst_n = 1 ;
end
always #1 sys_clk = ~sys_clk ;
ping_pang_1 ping_pang_1_1(
. sys_clk ( sys_clk ) ,
. rst_n ( rst_n ) ,
. doutb1 (doutb1 ) ,
. doutb2 (doutb2 )
);
endmodule
五、仿真结果
六、记录一些小问题:
(2)
(3)
所以修改思路就是尽量让enb1和enb2之间没有空隙,在时序上是衔接着的