上篇文章的异步fifo知道了长度信息,这次采用fifo存储长度信息,ram存储信号。
// An highlighted block
module fifo_ram (
input i_per_clk ,
input i_per_rst ,
input [11:0] i_per_data ,
input i_per_last ,
input i_per_valid ,
output o_per_ready ,
input i_post_clk ,
input i_post_rst ,
output [11:0] o_post_data ,
output o_post_last ,
output o_post_valid ,
input i_post_ready
/*-----------------*USER INTERFACE*-----------------*/
/*-----------------*DRIVE INTERFACE*-----------------*/
);
/*-----------------*function*-----------------*/
/*-----------------*parameter*----------------*/
/*-----------------*port*---------------------*/
/*-----------------*mechine*------------------*/
/*-----------------*reg*----------------------*/
reg [ 6:0] r_ram_addr_A ;
reg [ 6:0] r_ram_addr_B =0;
reg ro_per_ready ;
reg [11:0] r_per_len =0;
reg ri_per_last=0 ;
reg ro_post_valid =0 ;
reg ro_post_last=0 ;
reg r_data_rdb =0;
reg r_fifo_len_rd_en=0 ;
reg [11:0] r_read_cnt =0;
reg r_fifo_len_wr_en=0;
reg r_ram_data_rd =0 ;
reg r_ram_data_rd_1d=0 ;
reg r_ram_data_rd_2d=0 ;
reg [11:0] ro_post_data ;
/*-----------------*wire*---------------------*/
wire [11:0] w_ram_doutb;
wire [11:0] w_fifo_len_dout ;
wire w_fifo_len_full ;
wire w_fifo_len_empty ;
/*-----------------*assign*-------------------*/
assign w_per_active = i_per_valid & o_per_ready ;
assign w_post_active = o_post_valid & i_post_ready;
assign o_per_ready=ro_per_ready;
assign o_post_valid=ro_post_valid;
assign o_post_last=ro_post_last;
assign o_post_data =ro_post_data ;
/*-----------------*component*----------------*/
fifo_generator_0 your_12x64_u0 (
.wr_clk (i_per_clk ),// input wire wr_clk
.rd_clk (i_post_clk ),// input wire rd_clk
.din (r_per_len ),// input wire [11 : 0] din
.wr_en (r_fifo_len_wr_en ),// input wire wr_en
.rd_en (r_fifo_len_rd_en ),// input wire rd_en
.dout (w_fifo_len_dout ),// output wire [11 : 0] dout
.full (w_fifo_len_full ),// output wire full
.empty (w_fifo_len_empty ) // output wire empty
);
ram_12x100 ram_12x100_u0 (
.clka (i_per_clk ),// input wire clka
.ena (i_per_valid ),// input wire ena
.wea (i_per_valid ),// input wire [0 : 0] wea
.addra (r_ram_addr_A ),// input wire [6 : 0] addra
.dina (i_per_data ),// input wire [11 : 0] dina
.douta ( ),// output wire [11 : 0] douta
.clkb (i_post_clk ),// input wire clkb
.enb (r_ram_data_rd ),// input wire enb
.web (0 ),// input wire [0 : 0] web
.addrb (r_ram_addr_B ),// input wire [6 : 0] addrb
.dinb (0 ),// input wire [11 : 0] dinb
.doutb (w_ram_doutb ) // output wire [11 : 0] doutb
);
/*-----------------*always*-------------------*/
/*-----------------*per信号*-------------------*/
//数据开始写入
always @(posedge i_per_clk , posedge i_per_rst)
begin
if(i_per_rst)
begin
r_ram_addr_A<='d0;
end else if(i_per_last) begin
r_ram_addr_A<='d0;
end else if(i_per_valid) begin
r_ram_addr_A<=r_ram_addr_A+1;
end else begin
r_ram_addr_A<='d0;
end
end
always@(posedge i_per_clk) //和addr a保持同步
begin
if(i_per_valid)
r_per_len <= r_ram_addr_A;
else
r_per_len <= r_per_len;
end
always@(posedge i_per_clk)
begin
ri_per_last<=i_per_last;
end
//把长度信息写入进去 为w_fifo_len_dout
always@(posedge i_per_clk)
begin
if (i_per_last & !ri_per_last) begin //检测上升沿
r_fifo_len_wr_en<='d1;
end else begin
r_fifo_len_wr_en<='d0;
end
end
//fifo写入之后开始读取 (这个工作属于下一个时钟的工作)
/*-------post--------------------*/
always@(posedge i_post_clk)
begin
if(!w_fifo_len_empty) //读取到w_fifo_len_dout
r_fifo_len_rd_en <= 'd1;
else
r_fifo_len_rd_en <= 'd0;
end
always@(posedge i_post_clk)
begin
if(r_read_cnt == w_fifo_len_dout)
r_read_cnt <= 'd0;
else if(r_ram_data_rd)
r_read_cnt <= r_read_cnt + 1;
else
r_read_cnt <= r_read_cnt;
end
always @(posedge i_post_clk , posedge i_post_rst)
begin
if(r_read_cnt == w_fifo_len_dout)
begin
r_ram_data_rd<='d0;
end else if( r_fifo_len_rd_en) begin //读取的信号
r_ram_data_rd<='d1;
end else begin
r_ram_data_rd<=r_ram_data_rd;
end
end
always @(posedge i_post_clk )
begin
r_ram_data_rd_1d<=r_ram_data_rd;
r_ram_data_rd_2d<=r_ram_data_rd_1d;
ro_post_data <=w_ram_doutb;
end
//ram 读潜伏期 +ro_data赋值一个周期
always @(posedge i_post_clk)
begin
if( !r_ram_data_rd_1d & r_ram_data_rd_2d)//down
begin
ro_post_valid<='d0;
end else if(r_ram_data_rd_1d & !r_ram_data_rd_2d) begin //up
ro_post_valid<='d1;
end else begin
ro_post_valid<=ro_post_valid;
end
end
//观察到rd的下降沿作为一个条件
always @(posedge i_post_clk )
begin
if(!r_ram_data_rd & r_ram_data_rd_1d)
ro_post_last<='d1;
else
ro_post_last<='d0;
end
always @(posedge i_post_clk , posedge i_post_rst)
begin
if(r_read_cnt == w_fifo_len_dout)
r_ram_addr_B<='d0;
else if(r_ram_data_rd)
r_ram_addr_B<=r_ram_addr_B+1;
else
r_ram_addr_B<='d0;
end
//检测是否快满
always@(posedge i_per_clk,posedge i_per_rst)
begin
if(i_per_rst)
ro_per_ready <= 'd0;
else if(r_ram_addr_B==55) //快满了 一帧数据50
ro_per_ready <= 'd0;
else
ro_per_ready <= 'd1;
end
endmodule
// An highlighted block
module fifo_ram_tb(
);
reg clk,rst;
reg clk_f,rst_f;
always
begin
clk = 0;
#10;
clk = 1;
#10;
end
initial begin
rst = 1;
#100@(posedge clk)rst <= 0;//同步释放
end
always
begin
clk_f = 0;
#5;
clk_f = 1;
#5;
end
initial begin
rst_f = 1;
#100@(posedge clk_f)rst_f <= 0; //同步释放
end
// Parameters
//Ports
reg [11:0] r_per_data ;
reg r_per_last ;
reg r_per_valid ;
fifo_ram fifo_ram_inst (
.i_per_clk (clk ),
.i_per_rst (rst ),
.i_per_data (r_per_data ),
.i_per_last (r_per_last ),
.i_per_valid (r_per_valid ),
.o_per_ready ( ),
.i_post_clk (clk_f ),
.i_post_rst (rst_f ),
.o_post_data ( ),
.o_post_last ( ),
.o_post_valid ( ),
.i_post_ready (1 )
);
initial
begin
r_per_data = 0;
r_per_last = 0;
r_per_valid = 0;
wait(!rst);
forever begin
repeat(10)@(posedge clk);//运行10个空周期
per_send(10);
repeat(10)@(posedge clk);
per_send(20);
repeat(10)@(posedge clk);
per_send(30);
repeat(10)@(posedge clk);
end
end
reg [11:0] cnt ;
task per_send(input [15:0] len);
begin:per_send_task
integer i;
r_per_data <= 'd0;
r_per_last <= 'd0;
r_per_valid <= 'd0;
cnt <= 'd0;
@(posedge clk);
for(i = 0;i < len;i = i + 1)
begin
r_per_data <= cnt;
if(i == len - 1)r_per_last <= 'd1;
else r_per_last <= 'd0;
r_per_valid <= 'd1;
cnt <= cnt + 1;
@(posedge clk);
end
r_per_data <= 'd0;
r_per_last <= 'd0;
r_per_valid <= 'd0;
cnt <= 'd0;
@(posedge clk);
end
endtask
endmodule