ピンポン

6457 ワード

module ping_pong_buffer(
	input clk,
	input rst_n,
	
	//external write interface
	input[7:0] i_data,
	input i_data_valid,
	
	//ping ram buffer interface
	output ping_ram_buffer_wclk,
	output ping_ram_buffer_wea,
	output[9:0] ping_ram_buffer_w_addr,
	output[7:0] ping_ram_buffer_w_data,
	output ping_ram_buffer_rclk,
	output[8:0] ping_ram_buffer_r_addr,
	input[15:0] ping_ram_buffer_r_data,
	
	//pong ram buffer interface
	output pong_ram_buffer_wclk,
	output pong_ram_buffer_wea,
	output[9:0] pong_ram_buffer_w_addr,
	output[7:0] pong_ram_buffer_w_data,
	output pong_ram_buffer_rclk,
	output[8:0] pong_ram_buffer_r_addr,
	input[15:0] pong_ram_buffer_r_data,
	
	//internal read interface
	input	r_clk,
	output	o_data_valid,//256x16
	output[15:0]	o_data
);

	reg i_data_valid_delay_1,i_data_valid_delay_2;
	reg wr_buffer_sel;
	reg ping_buffer_wea,pong_buffer_wea;
	reg[9:0] ping_buffer_wr_addr,pong_buffer_wr_addr;	
	reg wr_finish;
	
	
	reg wr_finish_sync1,wr_finish_sync2,wr_finish_sync3;
	reg[8:0] buffer_rd_addr;
	reg buffer_rd_ena,buffer_rd_ena_delay;
	reg buffer_rd_sel;
	
	
	//-------------------------------write operation--------------------------------//
	always@(posedge clk)begin
		if(rst_n == 1'b0)begin
			i_data_valid_delay_1 <= 1'b0;
			i_data_valid_delay_2 <= 1'b0;
		end	
		else begin
			i_data_valid_delay_1 <= i_data_valid;
			i_data_valid_delay_2 <= i_data_valid_delay_1;
		end
	end

	always@(posedge clk)begin
		if(rst_n == 1'b0)
			wr_buffer_sel <= 1'b0;
		else if(i_data_valid == 1'b0 && i_data_valid_delay_1 == 1'b1)
			wr_buffer_sel <= ~wr_buffer_sel;
	end
	
	always@* begin
		ping_buffer_wea <= ~wr_buffer_sel & i_data_valid;
		pong_buffer_wea <= wr_buffer_sel & i_data_valid;
	end
	
	assign ping_ram_buffer_wea = ping_buffer_wea;
	assign pong_ram_buffer_wea = pong_buffer_wea;
	assign ping_ram_buffer_wclk = clk;
	assign pong_ram_buffer_wclk = clk;
	assign ping_ram_buffer_w_data = i_data;
	assign pong_ram_buffer_w_data = i_data;
	
	always@(posedge clk)begin
		if(rst_n == 1'b0)
			ping_buffer_wr_addr <= 10'b0;
		else if(ping_buffer_wea == 1'b1)
			ping_buffer_wr_addr <= ping_buffer_wr_addr+1;
		else
			ping_buffer_wr_addr <= 10'b0;
	end
	
	always@(posedge clk)begin
		if(rst_n == 1'b0)
			pong_buffer_wr_addr <= 10'b0;
		else if(pong_buffer_wea == 1'b1)
			pong_buffer_wr_addr <= pong_buffer_wr_addr+1;
		else
			pong_buffer_wr_addr <= 10'b0;
	end
	
	assign ping_ram_buffer_w_addr = ping_buffer_wr_addr;
	assign pong_ram_buffer_w_addr = pong_buffer_wr_addr;
	
	always@(posedge clk)begin
		if(rst_n == 1'b0)
			wr_finish <= 1'b0;
		else if(i_data_valid == 1'b0 && i_data_valid_delay_2 == 1'b1)
			wr_finish <= 1'b1;
		else
			wr_finish <= 1'b0;
	end
	
	//-----------------------------read operation--------------------------------//
	assign ping_ram_buffer_rclk = r_clk;
	assign pong_ram_buffer_rclk = r_clk;
	
	always@(r_clk)begin
		if(rst_n == 1'b0)begin
			wr_finish_sync1 <= 1'b0;
			wr_finish_sync2 <= 1'b0;
			wr_finish_sync3 <= 1'b0;
		end
		else begin
			wr_finish_sync1 <= wr_finish;
			wr_finish_sync2 <= wr_finish_sync1;
			wr_finish_sync3 <= wr_finish_sync2;
		end
	end
	
	always@(r_clk)begin
		if(rst_n == 1'b0)
			buffer_rd_ena <= 1'b0;
		else if(wr_finish_sync2 == 1 && wr_finish_sync3 == 0)
			buffer_rd_ena <= 1'b1;
		else if(buffer_rd_addr == 9'd511)
			buffer_rd_ena <= 1'b0;
	end
	
	always@(r_clk)begin
		if(rst_n == 1'b0)
			buffer_rd_ena_delay <= 1'b0;
		else 
			buffer_rd_ena_delay <= buffer_rd_ena;
	end
	
	always@(r_clk)begin
		if(rst_n == 1'b0)
			buffer_rd_addr <= 9'b0;
		else if(buffer_rd_ena)
			buffer_rd_addr <= buffer_rd_addr + 1;
		else 
			buffer_rd_addr <= 9'b0;
	end
	
	always@(r_clk)begin
		if(rst_n == 1'b0)
			buffer_rd_sel <= 1'b0;
		else if(buffer_rd_ena == 1'b0 && buffer_rd_ena_delay == 1'b1)
			buffer_rd_sel <= ~buffer_rd_sel;
	end
	
	assign ping_ram_buffer_r_addr = (buffer_rd_sel == 1'b0)?buffer_rd_addr:9'b0;
	assign pong_ram_buffer_r_addr = (buffer_rd_sel == 1'b1)?buffer_rd_addr:9'b0;
	
	assign o_data = (buffer_rd_sel == 1'b0)?ping_ram_buffer_r_data:pong_ram_buffer_r_data;
	assign o_data_valid = buffer_rd_ena_delay;
	
endmodule

testbenchの作成:
`timescale 1ns/1ns
`define clock_period 10

module tb_ping_pong_buffer;
	
	reg clk;
	reg rst_n;
	
	wire wclk,rclk;
	wire ping_ram_buffer_wea,pong_ram_buffer_wea;
	wire[9:0] ping_ram_buffer_w_addr,pong_ram_buffer_w_addr;
	wire[7:0] ping_ram_buffer_w_data,pong_ram_buffer_w_data;
	wire[8:0] ping_ram_buffer_r_addr,pong_ram_buffer_r_addr;
	wire [15:0] ping_ram_buffer_r_data,pong_ram_buffer_r_data;
	
	reg i_data_valid;
	reg [7:0] i_data;
	wire o_data_valid;
	wire[7:0] o_data;
	integer i;
	
	
	ping_pong_buffer inst1(
		.clk(clk),
		.rst_n(rst_n),
		
		//external write interface
		.i_data(i_data),
		.i_data_valid(i_data_valid),
		
		//ping ram buffer interface
		.ping_ram_buffer_wclk(wclk),
		.ping_ram_buffer_wea(ping_ram_buffer_wea),
		.ping_ram_buffer_w_addr(ping_ram_buffer_w_addr),
		.ping_ram_buffer_w_data(ping_ram_buffer_w_data),
		.ping_ram_buffer_rclk(rclk),
		.ping_ram_buffer_r_addr(ping_ram_buffer_r_addr),
		.ping_ram_buffer_r_data(ping_ram_buffer_r_data),
		
		//pong ram buffer interface
		.pong_ram_buffer_wclk(wclk),
		.pong_ram_buffer_wea(pong_ram_buffer_wea),
		.pong_ram_buffer_w_addr(pong_ram_buffer_w_addr),
		.pong_ram_buffer_w_data(pong_ram_buffer_w_data),
		.pong_ram_buffer_rclk(rclk),
		.pong_ram_buffer_r_addr(pong_ram_buffer_r_addr),
		.pong_ram_buffer_r_data(pong_ram_buffer_r_data),
		
		//internal read interface
		.r_clk(clk),
		.o_data_valid(o_data_valid),//256x16
		.o_data(o_data)
	);
	
	initial clk = 1;
	always #(`clock_period/2) clk = ~clk;
	
	initial begin
		rst_n = 1'b0;
		#(`clock_period*100+1);
		rst_n = 1'b1;
		i_data_valid = 1'b0;
		i_data = 8'b0;
		#(`clock_period*20);
		
		for (i=0;i<=1023;i=i+1)begin
			i_data_valid = 1;
			i_data = i;
			#`clock_period;
		end
		i_data_valid = 1'b0;
		
		#(`clock_period*20);
		for (i=0;i<=1023;i=i+1)begin
			i_data_valid = 1;
			i_data = i;
			#`clock_period;
		end
		i_data_valid = 1'b0;
		
		#(`clock_period*600);
		
		$stop;
	end

endmodule