一、系统结构
分为四个模块。外部控制单元,SWR_fifo,AXI_fifo,SRIO IP核。之间的主要连线关系如图所示。
二、外部控制单元。
此单元用来产生需要发送的数据data以及写使能信号wen。主要产生的过程比较简单。这里发送720*576byte的数据,由于SRIO是64bit的数据 因此,将数据进行组合发送,共发送64bit的数据个数为 720*576/8 = 51480
always @(posedge sys_clk)
begin
if (~sys_rstn)
begin
k7_srio_dma_wren <= 1'b0;
cnt_data <= 16'd0;
end
else
begin
if ((cnt_40ms >= 24'd1) && (cnt_40ms <= 24'd51840))
begin // 720x576=414720 byte
k7_srio_dma_wren <= 1'b1;
cnt_data <= cnt_data + 1; //发送的数据++
end
else
begin
k7_srio_dma_wren <= 1'b0;
cnt_data <= 16'd0;
end
end
end
assign k7_srio_dma_data = {4{cnt_data[7:0], cnt_data[15:8]}}; //64bit SRIO要发送的数据
三、SWR_fifo
用于缓存输入的数据,在状态机进入SWRITE之后,读取出数据。
fwft_fifo_w64 swr_fifo
(
.rst (inner_log_rst ),
.wr_clk (user_dma_clk ),
.wr_en (user_dma_en ),
.din (user_dma_data ),
.prog_full_thresh (9'd470 ),
.prog_full (user_dma_full ),
.full ( ),
.rd_clk (log_clk ),
.rd_en (dma_read_en ), //swr fifo读使能
.dout (dma_data_out ), //swr fifo读数据
.empty (user_dma_emtpy),
.prog_empty_thresh (9'd29 ),
.prog_empty (dma_fifo_empty),
.rd_data_count ( )
);
四、AXI_fifo
SWR_fifo输出的数据dma_data_out在传输过程中赋值给ireq_tdata。ireq_tvalid, ireq_tdata, ireq_tlast再组合成64bit的数据axi_fifo_din输入fifo
assign axi_fifo_din = {ireq_tvalid, ireq_tdata, ireq_tlast}; //axi fifo输入数据 ireq_tdata位主要部分 是将要发送的数据
// ================================== 发送数据的fifo FIFO Depth: 512 ============================//
fwft_fifo_w66 axi_fifo //66bit in 66 bit out
(
.clk (log_clk ),
.rst (inner_log_rst ),
.wr_en (axi_fifo_wren ), //ireq_tvalid 发送数据过程中 持续拉高
.din (axi_fifo_din ), //将swr的fifo输出数据 经过数据组装之后 写入axi fifo
.full ( ),
.prog_full (axi_fifo_full ),
.prog_full_thresh (9'd470 ),
.rd_en (axi_fifo_rden ), //val_ireq_tready SRIO IP核传来
.dout (axi_fifo_dout ), //传给SRIO IP核
.empty (axi_fifo_empty )
);
AXI fifo的读使能信号由SRIO模块传来。
assign axi_fifo_rden = ~axi_fifo_empty && val_ireq_tready; //axi fifo读使能
五、SRIO IP核模块
output val_ireq_tvalid, // AXI fifo使能信号
input val_ireq_tready, // IP核valid信号
output val_ireq_tlast, // Indicates the last beat of a packet
output [63:0] val_ireq_tdata, // 数据
output [7:0] val_ireq_tkeep, // 0xff
output [31:0] val_ireq_tuser, // src_id, dest_id
和IP核相关的主要由以上几个信号
六、状态机控制
IREQ_SWRITE_PRE: //每一帧数据的第一个状态,主要用于地址的重载 第一包数据用于重新加载地址 后续的地址+=256 无需进入这个状态
begin
cstate <= IREQ_SWRITE_HDR;
first_dma_flag <= 1'b0;
end
IREQ_SWRITE_HDR:// send swrite HELLO head
begin
cstate <= IREQ_SWRITE;
ireq_tvalid <= 1'b1; //axi fifo的读使能拉高 往fifo写入数据
ireq_tlast <= 1'b0;
//hello format的头部
ireq_tdata <= { 8'h00, // R
SWRITE, // FTYPE
4'b0000, // R
1'b0, // R
2'b00, // prio
1'b0, // crf
8'h00, // R
1'b0, // R
1'b0, // R
2'b00, dma_wr_addr // addr
};
dma_read_en <= 1'b1; //swr_fifo的读使能拉高
end
IREQ_SWRITE: // send DMA data
begin
if ( !srio_initialized_r2 ) begin
cstate <= IREQ_INIT;
end else if ( dword_cnt == ( DMA_THRESHOLD - 1 )) begin //读取完毕32个64bit的数据之后
cstate <= IREQ_SWRITE_WAIT;
ireq_tlast <= 1'b1;
end else begin
cstate <= IREQ_SWRITE;
end
ireq_tdata <= dma_data_out; //swr_fifo输出的数据 读取将要发送的数据
if ( dword_cnt == ( DMA_THRESHOLD - 1 )) //dword_cnt读出的数据 DMA_THRESHOLD=32 一包256字节 由于从fifo读出的是64bit的数据 所以这里的个数是256/8
begin
dma_read_en <= 1'b0; //发送完一包数据 256个
end
else
begin
dma_read_en <= 1'b1;
end
end
IREQ_SWRITE_WAIT: // wait one package SWRITE data send done
begin
if( !srio_initialized_r2 )
begin
cstate <= IREQ_INIT;
end
else if ( swrite_cnt == single_dma_size_r2 ) //发送完毕720*576/8个数据之后
begin
cstate <= IREQ_SWRITE_DONE;
dma_wr_done_r <= 1'b1;
first_dma_flag <= 1'b1;
end
else
begin
cstate <= IREQ_IDLE; //开始准备发送下一包数据 从头开始进入状态机
end
ireq_tvalid <= 1'b0; //axi fifo的读使能拉低 停止向axi fifo写数据
ireq_tlast <= 1'b0;
end
IREQ_SWRITE_DONE: // DMA SWRITE done
begin
cstate <= IREQ_IDLE;
dma_wr_done_r <= 1'b0;
end
default:
begin
cstate <= IREQ_INIT;
ireq_tvalid <= 1'b0;
ireq_tlast <= 1'b0;
end
IREQ_SWRITE_PRE:状态机主要包括以下几个状态:每一帧数据的第一个状态,主要用于地址的重载 第一包数据用于重新加载地址 后续的地址+=256 无需进入这个状态
IREQ_SWRITE_HDR:发送第一个hello format格式包
IREQ_SWRITE:控制读取swr_fifo的个数。当读取了32个64bit的数据之后,拉低swr_fifo读使能。可以构成一个256Byte的包,可以发送出去,
IREQ_SWRITE_WAIT:等待发送完毕swrite_cnt个数据。注意,每次进入的是IREQ_IDLE状态 从最开始的状态机开始准备。知道发送的个数等于需要发送的个数,跳入下一个完成状态
IREQ_SWRITE_DONE:SRIO发送完成
//------------------------------------------------------------------------------------------
// dword_cnt Counter 用于SWRITE模式计数 从swr fifo中读取的数
//------------------------------------------------------------------------------------------
always @( posedge log_clk, posedge inner_log_rst ) begin
if ( inner_log_rst ) begin
dword_cnt <= 6'd0;
end else begin
if ( cstate == IREQ_SWRITE ) begin
dword_cnt <= dword_cnt + 1'b1;
end else if ( ireq_tlast ) begin
dword_cnt <= 6'd0;
end
end
end
//-------------------------------------------------------------------------------------------
// DMA Write Address 每次地址递增256
//-------------------------------------------------------------------------------------------
always @( posedge log_clk, posedge inner_log_rst ) begin
if ( inner_log_rst ) begin
dma_wr_addr <= 32'd0;
end else begin
if ( cstate == IREQ_SWRITE_PRE ) begin // 初始帧,载入地址
dma_wr_addr <= dma_addr_init_value;
end else if ( cstate == IREQ_SWRITE_HDR ) begin // Update DMA Write Address
dma_wr_addr <= dma_wr_addr + 256;
end
end
end
//-------------------------------------------------------------------------------------------
// SWRITE Counter 用于记录总共发送的数据
//-------------------------------------------------------------------------------------------
always @( posedge log_clk, posedge inner_log_rst ) begin
if ( inner_log_rst ) begin
swrite_cnt <= 24'd0;
end else begin
if ((cstate == IREQ_SWRITE_DONE) || (cstate == IREQ_INIT)) begin
swrite_cnt <= 24'd0;
end else if (cstate == IREQ_SWRITE_HDR) begin
swrite_cnt <= swrite_cnt + 1'b1;
end
end
end