学习实战篇---通用卷积神经网络加速器的verilog实现(一)---axi-lite实验
学习用zynq7000系列fpga实现卷积神经网络
最终是想在zynq7000系类的fpga上实现yolo系类,以及其他轻量型网络,第一阶段主要是学习AXI总线相关的知识,并在fpga上实现,第二阶段主要是卷积神经网络的相关函数如何映射到fpga上去,第三阶段主要是写驱动应用程序,并上板调试。
axi读写架构
一.AXI总线协议规范:
1.无论写操作和读操作,地址信息和控制信息将在数据传输之前进行信息传输
2.支持多种数据的传输
3.支持乱序传输
信息源通过VALID信号显示数据信息或者控制信息的有效性;
而接受方则利用READY信号表示可以接收相应的数据;
还有一个LAST信号表示在读数据通道或者写数据通道中最后一个有效数据的到达
二.AXI总线的握手机制
1.五个单向通道体系结构均采用同样的VALID/READY两个握手信号来进行地址信息,控制信息,写/读数据信息,以及应答信息的传输。
2.信息源产生的高电平有效的VALID信号标志出地址信息,控制信息以及数据信息,应答信息等多种信息的有效传输或接收;
3.目标源产生的同样为高电平有效的READY信号则表明了可以接收相对应的信息。
VALID和READY信号均为高电平有效,也只有两个信号都为高电平时,传输才能完成。
4.AXI总线协议同时也规范了在AXI maste与AXI slave主从设备的输入输出信号之间不允许存在任何组合逻辑
5.握手信号之间存在的相关性:在握手中死锁会发生带来信号传输的崩溃,不同模块之间的握手信号不存在任何相关性
三.工程搭建
`timescale 1 ns / 1 ps
module axi_lite_slave #
(
parameter integer C_S_AXI_DATA_WIDTH = 32,
parameter integer C_S_AXI_ADDR_WIDTH = 6 //地址位宽
)
(
input wire S_AXI_ACLK,
input wire S_AXI_ARESETN,
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
input wire [2 : 0] S_AXI_AWPROT,
input wire S_AXI_AWVALID,
output wire S_AXI_AWREADY,
input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
input wire S_AXI_WVALID,
output wire S_AXI_WREADY,
output wire [1 : 0] S_AXI_BRESP,
output wire S_AXI_BVALID,
input wire S_AXI_BREADY,
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
input wire [2 : 0] S_AXI_ARPROT,
input wire S_AXI_ARVALID,
output wire S_AXI_ARREADY,
output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
output wire [1 : 0] S_AXI_RRESP,
output wire S_AXI_RVALID,
input wire S_AXI_RREADY
);
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;
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
localparam integer OPT_MEM_ADDR_BITS = 4-1;
wire slv_reg_rden;
wire slv_reg_wren;
reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;
integer byte_index;
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;
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awready <= 1'b0;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
begin
axi_awready <= 1'b1;
end
else
begin
axi_awready <= 1'b0;
end
end
end
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)
begin
axi_awaddr <= S_AXI_AWADDR;
end
end
end
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)
begin
axi_wready <= 1'b1;
end
else
begin
axi_wready <= 1'b0;
end
end
end
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
axi_bvalid <= 0;
axi_bresp <= 2'b0;
end
else
begin
if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
begin
axi_bvalid <= 1'b1;
axi_bresp <= 2'b0;
end
else
begin
if (S_AXI_BREADY && axi_bvalid)
begin
axi_bvalid <= 1'b0;
end
end
end
end
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
axi_arready <= 1'b1;
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
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
axi_rvalid <= 1'b1;
axi_rresp <= 2'b0;
end
else if (axi_rvalid && S_AXI_RREADY)
begin
axi_rvalid <= 1'b0;
end
end
end
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rdata <= 0;
end
else
begin
if (slv_reg_rden)
begin
axi_rdata <= reg_data_out;
end
end
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg0;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg0 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d0) )
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
slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg1;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg1 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d1) )
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
slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg2;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg2 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d2) )
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
slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg3;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg3 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d3) )
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
slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg4;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg4 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d4) )
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
slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg5;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg5 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d5) )
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
slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg6;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg6 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d6) )
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
slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg7;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg7 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d7) )
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
slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg8;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg8 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d8) )
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
slv_reg8[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg9;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg9 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d9) )
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
slv_reg9[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg10;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg10 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d10) )
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
slv_reg10[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg11;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg11 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d11) )
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
slv_reg11[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg12;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg12 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d12) )
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
slv_reg12[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg13;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg13 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d13) )
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
slv_reg13[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg14;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg14 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d14) )
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
slv_reg14[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
reg [C_S_AXI_DATA_WIDTH-1:0]slv_reg15;
always @( posedge S_AXI_ACLK )
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg15 <= 0;
end
else
if(slv_reg_wren & (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]=='d15) )
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
slv_reg15[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
always @(*)
begin
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
'd0:reg_data_out<=slv_reg0;
'd1:reg_data_out<=slv_reg1;
'd2:reg_data_out<=slv_reg2;
'd3:reg_data_out<=slv_reg3;
'd4:reg_data_out<=slv_reg4;
'd5:reg_data_out<=slv_reg5;
'd6:reg_data_out<=slv_reg6;
'd7:reg_data_out<=slv_reg7;
'd8:reg_data_out<=slv_reg8;
'd9:reg_data_out<=slv_reg9;
'd10:reg_data_out<=slv_reg10;
'd11:reg_data_out<=slv_reg11;
'd12:reg_data_out<=slv_reg12;
'd13:reg_data_out<=slv_reg13;
'd14:reg_data_out<=slv_reg14;
'd15:reg_data_out<=slv_reg15;
default : reg_data_out <= 0;
endcase
end
endmodule
1.利用vivado工具封装成ip核
2.新建一个工程,添加ip核,搭建bd,添加ila片内逻辑分析仪
3.生成bit流
4.export hardware启动sdk,勾选include bit选项,准备编写驱动程序
5.创建一个新的app——hello world创建一个新的app——hello world
这里选helloworld 模板
6.下载bit流文件到fpga
修改驱动的c代码
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
int main()
{
init_platform();
print("Hello World\n\r");
*(unsigned int *)0x43C00000 = 100;//定义一个指针,指向第一个寄存器并赋值
xil_printf("reg0=%d\r\n",*(unsigned int *) 0x43C00000);//打印第一个寄存器的值
*(unsigned int *)0x43C00004 = 200;
xil_printf("reg1=%d\r\n",*(unsigned int *) 0x43C00004);
cleanup_platform();
return 0;
}
运行run as 结果如下:
7.使用ila在线抓波形
修改hellword.c代码如下:加一个循环让arm启动
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
int main()
{
init_platform();
print("Hello World\n\r");
while(1){
*(unsigned int *)0x43C00000 = 100;
xil_printf("reg0=%d\r\n",*(unsigned int *) 0x43C00000);
*(unsigned int *)0x43C00004 = 200;
xil_printf("reg1=%d\r\n",*(unsigned int *) 0x43C00004);
}
cleanup_platform();
return 0;
}
这里串口一直打印数据,表示arm正常启动了
8.打开vivado下载程序的界面
点击抓波形(三角形)按钮,发现没有抓到数据,是因为读写都很短,大约只需要1us,而串口打印需要100us,所以很难抓到读写的那一部分数据,所以要设置触发条件。
9.用axi_master模型进行仿真
`timescale 1ns / 1ps
module AXI_GP_M_BFM #
(
parameter C_M_AXI_DATA_WIDTH=32,
parameter C_M_AXI_ADDR_WIDTH=6
)
(
input M_AXI_ACLK,
input M_AXI_ARESETN,
//AR channel
output reg M_AXI_ARVALID,
input M_AXI_ARREADY,
output reg [C_M_AXI_ADDR_WIDTH-1:0]M_AXI_ARADDR,
output [2:0]M_AXI_ARPROT,//=3'b0
//Rd channel
input [C_M_AXI_DATA_WIDTH-1:0]M_AXI_RDATA,
input [1:0]M_AXI_RRESP,//ignore
input M_AXI_RVALID,
output reg M_AXI_RREADY,
//AW channel
output reg M_AXI_AWVALID,
input M_AXI_AWREADY,
output reg [C_M_AXI_ADDR_WIDTH-1:0]M_AXI_AWADDR,
output [2:0]M_AXI_AWPROT,//=3'h0
//Wr channel
output reg [C_M_AXI_DATA_WIDTH-1:0]M_AXI_WDATA,
output reg M_AXI_WVALID,
input M_AXI_WREADY,
output [C_M_AXI_DATA_WIDTH/8-1:0]M_AXI_WSTRB,//={(C_M_AXI_DATA_WIDTH/8){1'b1}}
//Wr Resp
input [1:0]M_AXI_BRESP,//ignore
input M_AXI_BVALID,
output reg M_AXI_BREADY
);
assign M_AXI_AWPROT=3'h0;
assign M_AXI_WSTRB={(C_M_AXI_DATA_WIDTH/8){1'b1}};
assign M_AXI_ARPROT=3'b0;
always @(negedge M_AXI_ARESETN)
begin
M_AXI_AWVALID<=0;
M_AXI_AWADDR<=0;
M_AXI_WDATA<=0;
M_AXI_WVALID<=0;
M_AXI_ARVALID<=0;
M_AXI_ARADDR<=0;
M_AXI_RREADY<=0;
end
always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN)
if(~M_AXI_ARESETN)
M_AXI_BREADY<=1'b0;
else
if(M_AXI_BVALID & ~M_AXI_BREADY)
M_AXI_BREADY<=1'b1;
else
if(M_AXI_BVALID & M_AXI_BREADY)
M_AXI_BREADY<=1'b0;
task write(input int unsigned addr,data);
begin
@(posedge M_AXI_ACLK) M_AXI_AWVALID<=1;M_AXI_AWADDR<=addr;M_AXI_WVALID<=1;M_AXI_WDATA<=data;
@(posedge M_AXI_ACLK);
while((M_AXI_WVALID|M_AXI_AWVALID)==1)
begin
if(M_AXI_AWREADY)
M_AXI_AWVALID<=0;
if(M_AXI_WREADY)
M_AXI_WVALID<=0;
@(posedge M_AXI_ACLK);
end
while(~(M_AXI_BVALID && M_AXI_BREADY)) @(posedge M_AXI_ACLK);
end
endtask
task read(input int unsigned addr,output int unsigned data);
begin
M_AXI_ARADDR<=addr;
@(posedge M_AXI_ACLK) M_AXI_ARVALID<=1;
@(posedge M_AXI_ACLK);
while(~(M_AXI_ARVALID && M_AXI_ARREADY)) @(posedge M_AXI_ACLK);
M_AXI_ARVALID<=0;
@(posedge M_AXI_ACLK);
while(~M_AXI_RVALID) @(posedge M_AXI_ACLK);
M_AXI_RREADY<=1;
@(posedge M_AXI_ACLK) M_AXI_RREADY<=0;
data=M_AXI_RDATA;
end
endtask
endmodule
testbench文件采用system verilog来写的,在testbench中将axi_lite和axi_master例化,然后再将其对应的端口连接到一起,上代码
`timescale 1ns / 1ps
module testbench;
bit M_AXI_ACLK;always #5 M_AXI_ACLK=~M_AXI_ACLK;
bit M_AXI_ARESETN;
parameter C_M_AXI_DATA_WIDTH=32;
parameter C_M_AXI_ADDR_WIDTH=6;
//AR channel
wire M_AXI_ARVALID;
wire M_AXI_ARREADY;
wire [C_M_AXI_ADDR_WIDTH-1:0]M_AXI_ARADDR;
wire [2:0]M_AXI_ARPROT;//=3'b0
//Rd channel
wire [C_M_AXI_DATA_WIDTH-1:0]M_AXI_RDATA;
wire [1:0]M_AXI_RRESP;//ignore
wire M_AXI_RVALID;
wire M_AXI_RREADY;
//AW channel
wire M_AXI_AWVALID;
wire M_AXI_AWREADY;
wire [C_M_AXI_ADDR_WIDTH-1:0]M_AXI_AWADDR;
wire [2:0]M_AXI_AWPROT;//=3'h0
//Wr channel
wire [C_M_AXI_DATA_WIDTH-1:0]M_AXI_WDATA;
wire M_AXI_WVALID;
wire M_AXI_WREADY;
wire [C_M_AXI_DATA_WIDTH/8-1:0]M_AXI_WSTRB;//={(C_M_AXI_DATA_WIDTH/8){1'b1}}
//Wr Resp
wire [1:0]M_AXI_BRESP;//ignore
wire M_AXI_BVALID;
wire M_AXI_BREADY;
int unsigned rdata;
initial
begin
M_AXI_ARESETN=1;
#30 M_AXI_ARESETN=0;
#30 M_AXI_ARESETN=1;
repeat(30) @(posedge M_AXI_ACLK);
u_AXI_GP_M_BFM.write(16,20); //这里写地址为0x16,写的数据为0d20
u_AXI_GP_M_BFM.read(16,rdata); //这里读地址为0X16
#100 $stop;
end
dut_axi_lite_slave u_dut_axi_lite_slave
(
M_AXI_ACLK,
M_AXI_ARESETN,
M_AXI_AWADDR,
M_AXI_AWPROT,
M_AXI_AWVALID,
M_AXI_AWREADY,
M_AXI_WDATA,
M_AXI_WSTRB,
M_AXI_WVALID,
M_AXI_WREADY,
M_AXI_BRESP,
M_AXI_BVALID,
M_AXI_BREADY,
M_AXI_ARADDR,
M_AXI_ARPROT,
M_AXI_ARVALID,
M_AXI_ARREADY,
M_AXI_RDATA,
M_AXI_RRESP,
M_AXI_RVALID,
M_AXI_RREADY
);
AXI_GP_M_BFM u_AXI_GP_M_BFM
(
M_AXI_ACLK,
M_AXI_ARESETN,
//AR channel
M_AXI_ARVALID,
M_AXI_ARREADY,
M_AXI_ARADDR,
M_AXI_ARPROT,//=3'b0
//Rd channel
M_AXI_RDATA,
M_AXI_RRESP,//ignore
M_AXI_RVALID,
M_AXI_RREADY,
//AW channel
M_AXI_AWVALID,
M_AXI_AWREADY,
M_AXI_AWADDR,
M_AXI_AWPROT,//=3'h0
//Wr channel
M_AXI_WDATA,
M_AXI_WVALID,
M_AXI_WREADY,
M_AXI_WSTRB,//={(C_M_AXI_DATA_WIDTH/8){1'b1}}
//Wr Resp
M_AXI_BRESP,//ignore
M_AXI_BVALID,
M_AXI_BREADY
);
endmodule
读写仿真均正确
更多推荐
所有评论(0)