乒乓操作原理
乒乓操作整体流程图如下图所示:
乒乓操作的原理简单点说就是:
控制两个存储RAM1和RAM2,当数据开始存储进入RAM1时,将RAM2的数据输出进行处理;当数据开始存储进入RAM2时,将RAM1的数据输出进行处理。
何时存储数据由输入数据流选择模块控制,何时输出,由输出数据流选择模块进行控制。
RTL 图
整体RTL图如图所示:
其中 :
controller为控制模块,主要生成控制两个选择模块的使能信号。
mux21为输入数据流选择模块,控制两个RAM数据流何时输入。
RAM1和RAM2为两个存储模块,用于存储输入的数据流。
mux22为输出数据流控制模块,用于选择两个RAM的数据流,进行输出。
代码编写
下面对各个模块代码进行具体介绍:
顶层模块:
module dpram_pingpang_top(
input clk,
input rst_n,
input [15:0] i_data,
output [15:0] o_data,
//test
output [7:0] o_addr,
output [7:0] o_addw
);
wire mux1_en;
wire mux2_en;
controller controller_m1(
.clk(clk),
.rst_n(rst_n),
.mux1_en(mux1_en),
.mux2_en(mux2_en)
);
wire wr_en1;
wire wr_en2;
mux21 mux21_m1(
.clk(clk),
.rst_n(rst_n),
.en1(mux1_en),
.wr_en1(wr_en1),
.wr_en2(wr_en2)
);
wire [15:0] o_data1;
DRAM DRAM_m1(
.clk(clk),
.rst_n(rst_n),
.data(i_data),
.wr_en(wr_en1),
.o_data(o_data1),
.o_addr(o_addr),
.o_addw(o_addw)
);
wire [15:0] o_data2;
DRAM DRAM_m2(
.clk(clk),
.rst_n(rst_n),
.data(i_data),
.wr_en(wr_en2),
.o_data(o_data2)
//.o_addr(o_addr),
//.o_addw(o_addw)
);
mux22 mux22_m1(
.clk(clk),
.rst_n(rst_n),
.wr_en(mux1_en),
.o_data1(o_data1),
.o_data2(o_data2),
.o_data(o_data)
);
endmodule
顶层模块主要包含控制模块controller,两个RAM模块,两个mux二选一模块。
控制模块 controller
module controller(
input clk,
input rst_n,
output reg mux1_en,
output reg mux2_en
);
reg [7:0] cnt; //0-255
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
cnt <= 'd0;
else if(cnt =='d255)
cnt <='d0;
else
cnt <= cnt +'d1;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
begin
mux1_en <='d0;
mux2_en <='d0;
end
else if(cnt <'d128)
begin
mux1_en <= 'd1;
mux2_en <= 'd0;
end
else if(cnt >'d127&&cnt <'d256)
begin
mux1_en <='d0;
mux2_en <='d1;
end
end
endmodule
控制模块主要控制两个mux选择器的使能信号。
输入数据二选一选择器mux21:
module mux21(
input clk,
input rst_n,
input en1,
output wr_en1,
output wr_en2
);
assign wr_en1 = en1;
assign wr_en2 =~en1;
endmodule
由controller模块可知:计数0-255,在0-127时往RAM1中写入数据,读取RAM2中的数据;128-255时,往RAM2中写入数据,读取RAM1中的数据。
RAM存储模块:
module DRAM(
input clk,
input rst_n,
input [15:0] data,
input wr_en,
output reg [15:0] o_data,
output reg [7:0] o_addr,
output reg [7:0] o_addw
);
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
begin
o_addr <='d0;
o_addw <='d0;
end
else if(wr_en)
begin
o_addw <=o_addw+'d1;
o_addr <='d0;
end
else if(!wr_en)
begin
o_addr <= o_addr +'d1;
o_addw <='d0;
end
end
reg [15:0] aRAM[127:0];
integer i;
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
begin
o_data <='d0;
for(i=0;i<=127;i=i+1)
aRAM[i] <='d0;
end
else if(wr_en)
begin
aRAM[o_addw]<=data;
o_data <='d0;
end
else if(!wr_en)
begin
o_data<=aRAM[o_addr];
end
end
endmodule
加入o_addr和o_addw两个信号用来观察RAM读和RAM写的地址,当RAM进行读操作时,o_addr地址每个时钟+1;当RAM进行写操作时,o_addw地址每个时钟+1.
输出数据二选一模块mux22:
module mux22(
input clk,
input rst_n,
input wr_en,
input [15:0] o_data1,
input [15:0] o_data2,
output [15:0] o_data
);
reg flag1;
reg flag2; //打两拍
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
begin
flag1 <='d0;
flag2 <='d0;
end
else
begin
flag1 <= wr_en;
flag2 <= flag1;
end
end
reg [15:0] din1;
reg [15:0] din2;
always@(posedge clk or negedge rst_n)
begin
if(rst_n ==1'b0)
begin
din1 <='d0;
din2 <='d0;
end
else
begin
din1 <=o_data1;
din2 <=o_data2;
end
end
assign o_data =(flag2=='d1)?din2:din1;
endmodule
对输出的数据进行选择,这里直接用controller模块输出的使能信号来控制即可。
进行仿真testbench测试后,其仿真如图所示:
RAM1和RAM2的使能信号en1和en2交替为高,这里拉出来RAM1模块的o_addr和o_addw信号,o_addr为0时表示RAM1此时为读操作,o_addw为高表示此时RAM1为写操作。文章来源:https://uudwc.com/A/z0yR
附工程代码(vivado版本2017.4)
https://download.csdn.net/download/weixin_44413306/87234366文章来源地址https://uudwc.com/A/z0yR