一、项目要求
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;elsecur_state <= IDLE;
always@(*)case(cur_state)IDLE :beginnext_state = W1; end W1 :beginif(addra1 == 14 && wea1)next_state = W2_R1;elsenext_state = cur_state;endW2_R1 :beginif(addra2 == 14 && wea2)next_state = W1_R2;elsenext_state = cur_state;endW1_R2 :beginif(addra1 == 14 && wea1)next_state = W2_R1;elsenext_state = cur_state;enddefault:;endcase
/写状态机
always@(posedge clk_50M)if(!rst_n)beginwea1 <= 0; addra1 <= 0;dina1 <= 0;wea2 <= 0; addra2 <= 0;dina2 <= 0; endelsecase(cur_state)IDLE :beginend W1 :beginif(addra1 == 15)wea1 <= 0;elsewea1 <= 1; if(wea1 == 1)dina1 <= dina1 + 8'h27 ;elsedina1 <= 0;if(wea1 == 1 && addra1 == 15)addra1 <= 0;else if(wea1 == 1) addra1 <= addra1 + 1;elseaddra1 <= addra1; endW2_R1:beginaddra1 <= 0;wea1 <= 0; /ram1的写使能关闭if(addra2 == 15)wea2 <= 0;elsewea2 <= 1; if(wea2 == 1)dina2 <= dina2 + 8'h19 ;elsedina2 <= 0;if(wea2 == 1 && addra2 == 15)addra2 <= 0;else if(wea2 == 1) addra2 <= addra2 + 1;elseaddra2 <= 0; endW1_R2:beginwea2 <= 0;addra2 <= 0; if(addra1 == 15)wea1 <= 0;elsewea1 <= 1; if(wea1 == 1)dina1 <= dina1 + 8'h27 ;elsedina1 <= 0;if(wea1 == 1 && addra1 == 15)addra1 <= 0;else if(wea1 == 1) addra1 <= addra1 + 1;elseaddra1 <= 0; enddefault:;endcase
读状态机
always@(negedge clk_25M)if(!rst_n)beginenb1 <= 0; addrb1 <= 0;enb2 <= 0; addrb2 <= 0; endelsecase(cur_state)IDLE :beginend W1 :beginendW2_R1 :beginenb2 <= 0; addrb2 <= 0;if(addrb1 == 7 && enb1)enb1 <= 0;elseenb1 <= 1;if(enb1 == 1 && addrb1 == 7)addrb1 <= 0;else if(enb1)addrb1 <= addrb1 + 1;elseaddrb1 <= 0; endW1_R2 :beginaddrb1 <= 0; enb1 <= 0;if(addrb2 == 7)enb2 <= 0;elseenb2 <= 1;if(enb2 == 1 && addrb2 == 7)addrb2 <= 0;else if(enb2)addrb2 <= addrb2 + 1;elseaddrb2 <= 0; enddefault:;endcaseendmodule
五、仿真设计
`timescale 1ns / 1ps
module test_ping_pang( );reg sys_clk ;reg rst_n ;wire[15:0] doutb1 ;wire[15:0] doutb2 ;initialbeginsys_clk = 0 ;rst_n = 0 ;#10rst_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之间没有空隙,在时序上是衔接着的