赞
踩
因为最近要做项目,所以就学习了一下,但了解有限,再加上基础薄弱,所以仅限自我学习,有需要的同学也可以参考一下。
DataMover是Xilinx公司提供的一个免费IP,用于在DDR和PL端之间搬送数据(Xilinx的DataMover手册PG022中“AXI4 memory-mapped”表示PS端的DDR,AXI4-Stream domin表示PL端的数据流)。DataMover是DMA的基本原件,相比DMA,DataMover搬运数据的速度更快,更加有效率,但与此相对的,由于没有DMA封装完好的外壳,DataMover操控起来就更加复杂。
上图是Vivado中的DataMover IP模块及相应接口,除了时钟与复位接口之外,数据流分为MM2S和S2MM两种。其中的‘2’是to,‘MM’表示 memory-mapped,‘S’是Stream。
这条链路就是将数据从DDR读出到PL端。MM2S的核有两个FIFO通道,用于写入命令CMD,以及传输状态STS。CMD与STS的接口都是AXIS类型。当主机向DataMover写入MM2S_CMD命令后,内部将需要搬运数据的起始地址以及长度传入Read Engine,DataMover便开始从DDR中读出数据,同时,Read Engine将读出状态通过MM2S_STS传出,写入从机。
MM2S的接口并不多,连接起来也并不是很难。S_AXIS_MM2S_CMD连接PS的GP接口,或设置的命令寄存器;M_AXIS_MM2S连接状态寄存器,随时传输读出数据状态;M_AXI_MM2S通过PS连接DDR4,M_AXIS_MM2S连接PL端,可以放一个FIFO,当CMD正确传入后,DataMover就会自动取DDR中搬运数据,然后传输到PL。
在理解MM2S之后,S2MM理解与实现就简单多了。
因为没有具体实现S2MM,所以建议参考博客半小时速通ZYNQ PL端发送数据到PS DDR,他的block design的连接图如下所示:
但我也会建议你仔细看一下下一节后再来决定怎么实现S2MM。
首先讲一下链路:橘色是命令链路,绿色是数据链路。
在整个链路之中,AXI总线的理解是很重要的。
由于datamover的mm2s_cmd是AXIS接口,无法直接连接PS中GP的AXI接口,因此datamover与PS之间需要进行一个桥接;同时mm2s_tdata是72位寄存器,而PS中GP的wdata是32位,无法直接将命令数据写入mm2s_tdata命令寄存器,所以那个桥接还必须将写入命令存储起来,直到满足72位才行。
于是呢,我就自己生成了一个AXI总线转AXIS总线,并在其中存储3次32位有效数据,直到写满72位。当写满72位后,将m_axis_tvalid拉高一个时钟周期,完成cmd_tdata的数据写入。
主要代码如下:
reg slv_reg_wren_tap0;
reg slv_reg_wren_tap1;
reg slv_reg_wren_tap2;//写三次内存,每次写将相应位拉高
reg [71:0] s2m_tdata;
reg slv_reg_wren_d1;
reg slv_reg_wren_d2;//对slv_reg_wren打拍,才能将寄存器中的数据写入s2m_tdata
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN) begin
slv_reg_wren_d1 <= 1'b0;
slv_reg_wren_d2 <= 1'b0;
end
else begin
slv_reg_wren_d1 <= slv_reg_wren;
slv_reg_wren_d2 <= slv_reg_wren_d1;
end
end
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN) begin
s2m_tdata <= 72'd0;
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
else begin
if(slv_reg_wren_d2) begin
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0: begin
s2m_tdata <= {slv_reg0[7:0],s2m_tdata[63:0]};
slv_reg_wren_tap0 <= 1'b1;
end
2'h1: begin
s2m_tdata <= {s2m_tdata[71:64],slv_reg1,s2m_tdata[31:0]};
slv_reg_wren_tap1 <= 1'b1;
end
2'h2: begin
s2m_tdata <= {s2m_tdata[71:32],slv_reg2};
slv_reg_wren_tap2 <= 1'b1;
end
default : begin
s2m_tdata <= s2m_tdata;
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
endcase
end
else if(slv_reg_wren_tap0 && slv_reg_wren_tap1 && slv_reg_wren_tap2) begin
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
else begin
s2m_tdata <= s2m_tdata;
slv_reg_wren_tap0 <= slv_reg_wren_tap0;
slv_reg_wren_tap1 <= slv_reg_wren_tap1;
slv_reg_wren_tap2 <= slv_reg_wren_tap2;
end
end
end
reg slv_reg_wren_flag;//当tap0、tap1和tap2同时为1时,该信号拉高
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN)
slv_reg_wren_flag <= 1'b0;
else begin
if(slv_reg_wren_tap0 && slv_reg_wren_tap1 && slv_reg_wren_tap2)
slv_reg_wren_flag <= 1'b1;
else
slv_reg_wren_flag <= 1'b0;
end
end
assign S_AXI_OUT_TVALID = slv_reg_wren_flag;
assign S_OUT_S2M_TDATA = s2m_tdata;
接口 | 说明 |
---|---|
mm2s_err | 当在MM2S路径上发生错误时,会产生mm2s_err信号或标志(电平拉高) |
m_axis_mm2s_cmdsts_aclk | 当为异步模式(数据的读取和输入时钟不同)时,单独连接一个时钟,但时钟频率不能高于m_axi_mm2s_aclk;如果为非异步模式,则可以和m_axi_mm2s_aclk直连 |
m_axis_mm2s_cmdsts_aresetn | 当为异步模式时,单独连接一个复位,并且要先经过三个时钟周期才能被置位;为非异步模式时,可以和m_axi_mm2s_aresetn直连 |
S_AXIS_MM2S_CMD | 传入MM2S的命令 |
M_AXI_MM2S | 将传入MM2S的tdata分解成搬运数据的起始地址和数据长度,然后通过AXI总线写入PS,之后将DDR中的数据搬运出来 |
M_AXIS_MM2S_STS | 搬运数据的状态 |
M_AXIS_MM2S | 将搬运的数据通过AXIS总线传递到PL端 |
CMD有两种版本,一种是完整版(Full),一种是基本版(Basic):
根据程序进行仿真是没有问题的,但上板调却出现了一点问题,那就是AXI_to_AXIS的m00_axis_tready不主动拉高,于是需要手动拉高,这就是BD中VIO的作用。
增加内容
通过调试:虽然DDR为32位,但Memory Map Data Width需填写64位。因为搬运数据时是按照字节搬运,若填写为32,则搬运前4个字节后,继续搬运前4个字节,之后从第8个字节开始搬运,继续搬运第8至12个字节,如此往复。
举例:DDR中的数据是:01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
当Memory Map Data Width为32时,搬运的数据是:01 02 03 04 01 02 03 04 09 10 11 12 09 10 11 12 17 18 19
Maximum Burst Size表示一次搬运字节数量,且该值不能小于命令寄存器中的BTT值,否则搬运会出错。当一次搬运完成后,m_axi_mm2s_arready会被拉低一个时钟周期,之后想要搬运,需要重新完成一次命令寄存器的写入,猜测是将s_axis_mm2s_cmd_tvalid拉高一个时钟周期。
我知道你可能比较懒,那我就把AXI_to_AXI模块的代码放在这里哟(上传到网盘太麻烦了,直接把代码粘贴到下面):
下面只有代码啦
顶层文件AXI_to_AXIS:
`timescale 1 ns / 1 ps
module AXI_to_AXIS_v1_0 #
(
// Users to add parameters here
// User parameters ends
// Do not modify the parameters beyond this line
// Parameters of Axi Slave Bus Interface S00_AXI
parameter integer C_S00_AXI_DATA_WIDTH = 32,
parameter integer C_S00_AXI_ADDR_WIDTH = 32,
// Parameters of Axi Master Bus Interface M00_AXIS
parameter integer C_M00_AXIS_TDATA_WIDTH = 72,
parameter integer C_M00_AXIS_START_COUNT = 72
)
(
// Users to add ports here
// User ports ends
// Do not modify the ports beyond this line
// Ports of Axi Slave Bus Interface S00_AXI
input wire s00_axi_aclk,
input wire s00_axi_aresetn,
input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,
input wire [2 : 0] s00_axi_awprot,
input wire s00_axi_awvalid,
output wire s00_axi_awready,
input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,
input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,
input wire s00_axi_wvalid,
output wire s00_axi_wready,
output wire [1 : 0] s00_axi_bresp,
output wire s00_axi_bvalid,
input wire s00_axi_bready,
input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,
input wire [2 : 0] s00_axi_arprot,
input wire s00_axi_arvalid,
output wire s00_axi_arready,
output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,
output wire [1 : 0] s00_axi_rresp,
output wire s00_axi_rvalid,
input wire s00_axi_rready,
// Ports of Axi Master Bus Interface M00_AXIS
input wire m00_axis_aclk,
input wire m00_axis_aresetn,
output wire m00_axis_tvalid,
output wire [C_M00_AXIS_TDATA_WIDTH-1 : 0] m00_axis_tdata,
output wire [(C_M00_AXIS_TDATA_WIDTH/8)-1 : 0] m00_axis_tstrb,
output wire m00_axis_tlast,
input wire m00_axis_tready
);
wire [C_M00_AXIS_TDATA_WIDTH-1 : 0] s2m_m_axis_tdata;
wire m_axis_in_tvalid;
// Instantiation of Axi Bus Interface S00_AXI
AXI_to_AXIS_v1_0_S00_AXI # (
.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
) AXI_to_AXIS_v1_0_S00_AXI_inst (
.S_AXI_ACLK(s00_axi_aclk),
.S_AXI_ARESETN(s00_axi_aresetn),
.S_AXI_AWADDR(s00_axi_awaddr),
.S_AXI_AWPROT(s00_axi_awprot),
.S_AXI_AWVALID(s00_axi_awvalid),
.S_AXI_AWREADY(s00_axi_awready),
.S_AXI_WDATA(s00_axi_wdata),
.S_AXI_WSTRB(s00_axi_wstrb),
.S_AXI_WVALID(s00_axi_wvalid),
.S_AXI_WREADY(s00_axi_wready),
.S_AXI_BRESP(s00_axi_bresp),
.S_AXI_BVALID(s00_axi_bvalid),
.S_AXI_BREADY(s00_axi_bready),
.S_AXI_ARADDR(s00_axi_araddr),
.S_AXI_ARPROT(s00_axi_arprot),
.S_AXI_ARVALID(s00_axi_arvalid),
.S_AXI_ARREADY(s00_axi_arready),
.S_AXI_RDATA(s00_axi_rdata),
.S_AXI_RRESP(s00_axi_rresp),
.S_AXI_RVALID(s00_axi_rvalid),
.S_AXI_RREADY(s00_axi_rready),
.S_AXI_OUT_TVALID(m_axis_in_tvalid),
.S_OUT_S2M_TDATA(s2m_m_axis_tdata)
);
// Instantiation of Axi Bus Interface M00_AXIS
AXI_to_AXIS_v1_0_M00_AXIS # (
.C_M_AXIS_TDATA_WIDTH(C_M00_AXIS_TDATA_WIDTH),
.C_M_START_COUNT(C_M00_AXIS_START_COUNT)
) AXI_to_AXIS_v1_0_M00_AXIS_inst (
.M_AXIS_ACLK(m00_axis_aclk),
.M_AXIS_ARESETN(m00_axis_aresetn),
.M_AXIS_TVALID(m00_axis_tvalid),
.M_AXIS_TDATA(m00_axis_tdata),
.M_AXIS_TSTRB(m00_axis_tstrb),
.M_AXIS_TLAST(m00_axis_tlast),
.M_AXIS_TREADY(m00_axis_tready),
.M_AXIS_TOUT_DATA(s2m_m_axis_tdata),
.M_AXIS_IN_TVALID(m_axis_in_tvalid)
);
// Add user logic here
// User logic ends
endmodule
AXI_to_AXIS_v1_0_S00_AXI
`timescale 1 ns / 1 ps
module AXI_to_AXIS_v1_0_S00_AXI #
(
// Users to add parameters here
// User parameters ends
// Do not modify the parameters beyond this line
// Width of S_AXI data bus
parameter integer C_S_AXI_DATA_WIDTH = 32,
// Width of S_AXI address bus
parameter integer C_S_AXI_ADDR_WIDTH = 4
)
(
// Users to add ports here
output wire S_AXI_OUT_TVALID,
output wire [71:0] S_OUT_S2M_TDATA,
// User ports ends
// Do not modify the ports beyond this line
// Global Clock Signal
input wire S_AXI_ACLK,
// Global Reset Signal. This Signal is Active LOW
input wire S_AXI_ARESETN,
// Write address (issued by master, acceped by Slave)
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
// Write channel Protection type. This signal indicates the
// privilege and security level of the transaction, and whether
// the transaction is a data access or an instruction access.
input wire [2 : 0] S_AXI_AWPROT,
// Write address valid. This signal indicates that the master signaling
// valid write address and control information.
input wire S_AXI_AWVALID,
// Write address ready. This signal indicates that the slave is ready
// to accept an address and associated control signals.
output wire S_AXI_AWREADY,
// Write data (issued by master, acceped by Slave)
input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
// Write strobes. This signal indicates which byte lanes hold
// valid data. There is one write strobe bit for each eight
// bits of the write data bus.
input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
// Write valid. This signal indicates that valid write
// data and strobes are available.
input wire S_AXI_WVALID,
// Write ready. This signal indicates that the slave
// can accept the write data.
output wire S_AXI_WREADY,
// Write response. This signal indicates the status
// of the write transaction.
output wire [1 : 0] S_AXI_BRESP,
// Write response valid. This signal indicates that the channel
// is signaling a valid write response.
output wire S_AXI_BVALID,
// Response ready. This signal indicates that the master
// can accept a write response.
input wire S_AXI_BREADY,
// Read address (issued by master, acceped by Slave)
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
// Protection type. This signal indicates the privilege
// and security level of the transaction, and whether the
// transaction is a data access or an instruction access.
input wire [2 : 0] S_AXI_ARPROT,
// Read address valid. This signal indicates that the channel
// is signaling valid read address and control information.
input wire S_AXI_ARVALID,
// Read address ready. This signal indicates that the slave is
// ready to accept an address and associated control signals.
output wire S_AXI_ARREADY,
// Read data (issued by slave)
output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
// Read response. This signal indicates the status of the
// read transfer.
output wire [1 : 0] S_AXI_RRESP,
// Read valid. This signal indicates that the channel is
// signaling the required read data.
output wire S_AXI_RVALID,
// Read ready. This signal indicates that the master can
// accept the read data and response information.
input wire S_AXI_RREADY
);
// AXI4LITE signals
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;
reg axi_awready;
reg axi_wready;
reg [1 : 0] axi_bresp;
reg axi_bvalid;
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;
reg axi_arready;
reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;
reg [1 : 0] axi_rresp;
reg axi_rvalid;
// Example-specific design signals
// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
// ADDR_LSB is used for addressing 32/64 bit registers/memories
// ADDR_LSB = 2 for 32 bits (n downto 2)
// ADDR_LSB = 3 for 64 bits (n downto 3)
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
localparam integer OPT_MEM_ADDR_BITS = 1;
//----------------------------------------------
//-- Signals for user logic register space example
//------------------------------------------------
//-- Number of Slave Registers 4
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3;
wire slv_reg_rden;
wire slv_reg_wren;
reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;
integer byte_index;
reg aw_en;
// I/O Connections assignments
assign S_AXI_AWREADY = axi_awready;
assign S_AXI_WREADY = axi_wready;
assign S_AXI_BRESP = axi_bresp;
assign S_AXI_BVALID = axi_bvalid;
assign S_AXI_ARREADY = axi_arready;
assign S_AXI_RDATA = axi_rdata;
assign S_AXI_RRESP = axi_rresp;
assign S_AXI_RVALID = axi_rvalid;
// Implement axi_awready generation
// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
// de-asserted when reset is low.
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awready <= 1'b0;
aw_en <= 1'b1;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
// slave is ready to accept write address when
// there is a valid write address and write data
// on the write address and data bus. This design
// expects no outstanding transactions.
axi_awready <= 1'b1;
aw_en <= 1'b0;
end
else if (S_AXI_BREADY && axi_bvalid)
begin
aw_en <= 1'b1;
axi_awready <= 1'b0;
end
else
begin
axi_awready <= 1'b0;
end
end
end
// Implement axi_awaddr latching
// This process is used to latch the address when both
// S_AXI_AWVALID and S_AXI_WVALID are valid.
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awaddr <= 0;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
// Write Address latching
axi_awaddr <= S_AXI_AWADDR;
end
end
end
// Implement axi_wready generation
// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is
// de-asserted when reset is low.
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_wready <= 1'b0;
end
else
begin
if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )
begin
// slave is ready to accept write data when
// there is a valid write address and write data
// on the write address and data bus. This design
// expects no outstanding transactions.
axi_wready <= 1'b1;
end
else
begin
axi_wready <= 1'b0;
end
end
end
// Implement memory mapped register select and write logic generation
// The write data is accepted and written to memory mapped registers when
// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
// select byte enables of slave registers while writing.
// These registers are cleared when reset (active low) is applied.
// Slave register write enable is asserted when valid address and data are available
// and the slave is ready to accept the write address and write data.
assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg0 <= 0;
slv_reg1 <= 0;
slv_reg2 <= 0;
slv_reg3 <= 0;
end
else begin
if (slv_reg_wren)
begin
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
// Respective byte enables are asserted as per write strobes
// Slave register 0
slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h1:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
// Respective byte enables are asserted as per write strobes
// Slave register 1
slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h2:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
// Respective byte enables are asserted as per write strobes
// Slave register 2
slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h3:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
// Respective byte enables are asserted as per write strobes
// Slave register 3
slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
default : begin
slv_reg0 <= slv_reg0;
slv_reg1 <= slv_reg1;
slv_reg2 <= slv_reg2;
slv_reg3 <= slv_reg3;
end
endcase
end
end
end
reg slv_reg_wren_tap0;
reg slv_reg_wren_tap1;
reg slv_reg_wren_tap2;//写三次内存,每次写将相应位拉高
reg [71:0] s2m_tdata;
reg slv_reg_wren_d1;
reg slv_reg_wren_d2;//对slv_reg_wren打拍,才能将寄存器中的数据写入s2m_tdata
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN) begin
slv_reg_wren_d1 <= 1'b0;
slv_reg_wren_d2 <= 1'b0;
end
else begin
slv_reg_wren_d1 <= slv_reg_wren;
slv_reg_wren_d2 <= slv_reg_wren_d1;
end
end
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN) begin
s2m_tdata <= 72'd0;
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
else begin
if(slv_reg_wren_d2) begin
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0: begin
s2m_tdata <= {slv_reg0[7:0],s2m_tdata[63:0]};
slv_reg_wren_tap0 <= 1'b1;
end
2'h1: begin
s2m_tdata <= {s2m_tdata[71:64],slv_reg1,s2m_tdata[31:0]};
slv_reg_wren_tap1 <= 1'b1;
end
2'h2: begin
s2m_tdata <= {s2m_tdata[71:32],slv_reg2};
slv_reg_wren_tap2 <= 1'b1;
end
default : begin
s2m_tdata <= s2m_tdata;
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
endcase
end
else if(slv_reg_wren_tap0 && slv_reg_wren_tap1 && slv_reg_wren_tap2) begin
slv_reg_wren_tap0 <= 1'b0;
slv_reg_wren_tap1 <= 1'b0;
slv_reg_wren_tap2 <= 1'b0;
end
else begin
s2m_tdata <= s2m_tdata;
slv_reg_wren_tap0 <= slv_reg_wren_tap0;
slv_reg_wren_tap1 <= slv_reg_wren_tap1;
slv_reg_wren_tap2 <= slv_reg_wren_tap2;
end
end
end
reg slv_reg_wren_flag;//当tap0、tap1和tap2同时为1时,该信号拉高
always @(posedge S_AXI_ACLK) begin
if(~S_AXI_ARESETN)
slv_reg_wren_flag <= 1'b0;
else begin
if(slv_reg_wren_tap0 && slv_reg_wren_tap1 && slv_reg_wren_tap2)
slv_reg_wren_flag <= 1'b1;
else
slv_reg_wren_flag <= 1'b0;
end
end
assign S_AXI_OUT_TVALID = slv_reg_wren_flag;
assign S_OUT_S2M_TDATA = s2m_tdata;
// Implement write response logic generation
// The write response and response valid signals are asserted by the slave
// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
// This marks the acceptance of address and indicates the status of
// write transaction.
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_bvalid <= 0;
axi_bresp <= 2'b0;
end
else
begin
if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
begin
// indicates a valid write response is available
axi_bvalid <= 1'b1;
axi_bresp <= 2'b0; // 'OKAY' response
end // work error responses in future
else
begin
if (S_AXI_BREADY && axi_bvalid)
//check if bready is asserted while bvalid is high)
//(there is a possibility that bready is always asserted high)
begin
axi_bvalid <= 1'b0;
end
end
end
end
// Implement axi_arready generation
// axi_arready is asserted for one S_AXI_ACLK clock cycle when
// S_AXI_ARVALID is asserted. axi_awready is
// de-asserted when reset (active low) is asserted.
// The read address is also latched when S_AXI_ARVALID is
// asserted. axi_araddr is reset to zero on reset assertion.
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_arready <= 1'b0;
axi_araddr <= 32'b0;
end
else
begin
if (~axi_arready && S_AXI_ARVALID)
begin
// indicates that the slave has acceped the valid read address
axi_arready <= 1'b1;
// Read address latching
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
// Implement axi_arvalid generation
// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both
// S_AXI_ARVALID and axi_arready are asserted. The slave registers
// data are available on the axi_rdata bus at this instance. The
// assertion of axi_rvalid marks the validity of read data on the
// bus and axi_rresp indicates the status of read transaction.axi_rvalid
// is deasserted on reset (active low). axi_rresp and axi_rdata are
// cleared to zero on reset (active low).
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rvalid <= 0;
axi_rresp <= 0;
end
else
begin
if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
begin
// Valid read data is available at the read data bus
axi_rvalid <= 1'b1;
axi_rresp <= 2'b0; // 'OKAY' response
end
else if (axi_rvalid && S_AXI_RREADY)
begin
// Read data is accepted by the master
axi_rvalid <= 1'b0;
end
end
end
// Implement memory mapped register select and read logic generation
// Slave register read enable is asserted when valid address is available
// and the slave is ready to accept the read address.
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
always @(*)
begin
// Address decoding for reading registers
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0 : reg_data_out <= slv_reg0;
2'h1 : reg_data_out <= slv_reg1;
2'h2 : reg_data_out <= slv_reg2;
2'h3 : reg_data_out <= slv_reg3;
default : reg_data_out <= 0;
endcase
end
// Output register or memory read data
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rdata <= 0;
end
else
begin
// When there is a valid read address (S_AXI_ARVALID) with
// acceptance of read address by the slave (axi_arready),
// output the read dada
if (slv_reg_rden)
begin
axi_rdata <= reg_data_out; // register read data
end
end
end
// Add user logic here
ila_0 ila_probc (
.clk(S_AXI_ACLK), // input wire clk
.probe0(slv_reg0), // input wire [31:0] probe0
.probe1(slv_reg1), // input wire [31:0] probe1
.probe2(slv_reg2), // input wire [31:0] probe2
.probe3(slv_reg3), // input wire [31:0] probe3
.probe4(slv_reg_wren), // input wire [0:0] probe4
.probe5(slv_reg_wren_d2), // input wire [0:0] probe5
.probe6(slv_reg_wren_flag), // input wire [0:0] probe6
.probe7(S_OUT_S2M_TDATA), // input wire [71:0] probe7
.probe8(slv_reg_wren_tap0), // input wire [0:0] probe8
.probe9(slv_reg_wren_tap1), // input wire [0:0] probe9
.probe10(slv_reg_wren_tap2), // input wire [0:0] probe10
.probe11(slv_reg_wren_flag), // input wire [0:0] probe11
.probe12(), // input wire [0:0] probe12
.probe13(), // input wire [0:0] probe13
.probe14(axi_awaddr) // input wire [31:0] probe14
);
// User logic ends
endmodule
AXI_to_AXIS_v1_0_M00_AXIS
`timescale 1 ns / 1 ps
module AXI_to_AXIS_v1_0_M00_AXIS #
(
// Users to add parameters here
// User parameters ends
// Do not modify the parameters beyond this line
// Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
parameter integer C_M_AXIS_TDATA_WIDTH = 32,
// Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
parameter integer C_M_START_COUNT = 32
)
(
// Users to add ports here
input wire [C_M_AXIS_TDATA_WIDTH-1:0] M_AXIS_TOUT_DATA,
input wire M_AXIS_IN_TVALID,
// User ports ends
// Do not modify the ports beyond this line
// Global ports
input wire M_AXIS_ACLK,
//
input wire M_AXIS_ARESETN,
// Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted.
output wire M_AXIS_TVALID,
// TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
// TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
// TLAST indicates the boundary of a packet.
output wire M_AXIS_TLAST,
// TREADY indicates that the slave can accept a transfer in the current cycle.
input wire M_AXIS_TREADY
);
// Total number of output data
localparam NUMBER_OF_OUTPUT_WORDS = 72;
// function called clogb2 that returns an integer which has the
// value of the ceiling of the log base 2.
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction
// WAIT_COUNT_BITS is the width of the wait counter.
localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);
// bit_num gives the minimum number of bits needed to address 'depth' size of FIFO.
localparam bit_num = clogb2(NUMBER_OF_OUTPUT_WORDS);
// Define the states of state machine
// The control state machine oversees the writing of input streaming data to the FIFO,
// and outputs the streaming data from the FIFO
parameter [1:0] IDLE = 2'b00, // This is the initial/idle state
INIT_COUNTER = 2'b01, // This state initializes the counter, once
// the counter reaches C_M_START_COUNT count,
// the state machine changes state to SEND_STREAM
SEND_STREAM = 2'b10; // In this state the
// stream data is output through M_AXIS_TDATA
// State variable
reg [1:0] mst_exec_state;
// Example design FIFO read pointer
reg [bit_num-1:0] read_pointer;
// AXI Stream internal signals
//wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
reg [WAIT_COUNT_BITS-1 : 0] count;
//streaming data valid
wire axis_tvalid;
//streaming data valid delayed by one clock cycle
reg axis_tvalid_delay;
//Last of the streaming data
wire axis_tlast;
//Last of the streaming data delayed by one clock cycle
reg axis_tlast_delay;
//FIFO implementation signals
reg [C_M_AXIS_TDATA_WIDTH-1 : 0] stream_data_out;
wire tx_en;
//The master has issued all the streaming data stored in FIFO
reg tx_done;
// I/O Connections assignments
assign M_AXIS_TVALID = axis_tvalid_delay;
//assign M_AXIS_TDATA = stream_data_out;
assign M_AXIS_TDATA = M_AXIS_TOUT_DATA;
assign M_AXIS_TLAST = axis_tlast_delay;
assign M_AXIS_TSTRB = {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};
// Control state machine implementation
always @(posedge M_AXIS_ACLK)
begin
if (!M_AXIS_ARESETN)
// Synchronous reset (active low)
begin
mst_exec_state <= IDLE;
count <= 0;
end
else
case (mst_exec_state)
IDLE:
// The slave starts accepting tdata when
// there tvalid is asserted to mark the
// presence of valid streaming data
//if ( count == 0 )
// begin
mst_exec_state <= INIT_COUNTER;
// end
//else
// begin
// mst_exec_state <= IDLE;
// end
INIT_COUNTER:
// The slave starts accepting tdata when
// there tvalid is asserted to mark the
// presence of valid streaming data
if ( count == C_M_START_COUNT - 1 )
begin
mst_exec_state <= SEND_STREAM;
end
else
begin
count <= count + 1;
mst_exec_state <= INIT_COUNTER;
end
SEND_STREAM:
// The example design streaming master functionality starts
// when the master drives output tdata from the FIFO and the slave
// has finished storing the S_AXIS_TDATA
if (tx_done)
begin
mst_exec_state <= IDLE;
end
else
begin
mst_exec_state <= SEND_STREAM;
end
endcase
end
//tvalid generation
//axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
//number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
//assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
assign axis_tvalid = M_AXIS_IN_TVALID;
// AXI tlast generation
// axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1
// (0 to NUMBER_OF_OUTPUT_WORDS-1)
assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);
//assign axis_tlast = M_AXIS_IN_TLAST;
// Delay the axis_tvalid and axis_tlast signal by one clock cycle
// to match the latency of M_AXIS_TDATA
always @(posedge M_AXIS_ACLK)
begin
if (!M_AXIS_ARESETN)
begin
axis_tvalid_delay <= 1'b0;
axis_tlast_delay <= 1'b0;
end
else
begin
axis_tvalid_delay <= axis_tvalid;
axis_tlast_delay <= axis_tlast;
end
end
//read_pointer pointer
always@(posedge M_AXIS_ACLK)
begin
if(!M_AXIS_ARESETN)
begin
read_pointer <= 0;
tx_done <= 1'b0;
end
else
if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)
begin
if (tx_en)
// read pointer is incremented after every read from the FIFO
// when FIFO read signal is enabled.
begin
read_pointer <= read_pointer + 1;
tx_done <= 1'b0;
end
end
else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)
begin
// tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data
// has been out.
tx_done <= 1'b1;
end
end
//FIFO read enable generation
assign tx_en = M_AXIS_TREADY && axis_tvalid;
// Streaming output data is read from FIFO
always @( posedge M_AXIS_ACLK )
begin
if(!M_AXIS_ARESETN)
begin
stream_data_out <= 1;
end
else if (tx_en)// && M_AXIS_TSTRB[byte_index]
begin
stream_data_out <= read_pointer + 32'b1;
end
end
// Add user logic here
// User logic ends
endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。