专业解释:
VIP(Verfication IP)代码确认与验证技术,是预先验证过的内建验证结构,提供了完整的、灵活的应用机制,可以方便地插入到基于仿真的确认测试中,可以大大提高验证可重用性和验证效率。VIP是一种验证模型,并提供一套全面测试环境,帮助设计者和验证者确认其设计功能的正确性,可用于各个层次的仿真验证。通常,VIP是基于标准协议的,如:AMBA、PCIE、USB、Ethernet等。VIP中包括很多验证部件IP,这些IP都严格遵循这些标准协议、已经被验证过,通常包括:产生testbench所必须的基础部件、检查机制以及产生单独协议的程序,这些程序通常是一个BFM(Bus Functional Models)。
通俗解释:
vip可以实现数据 → 通信协议的转换,把想发的数据输入给vip(如读文件的方式),vip会输出符合相应通信协议的数据,可直接用来作为相应模块的输入信号。
vip也可以用来验证输出数据是否符合相应通信协议的时序,且输出的数据是否正确(与文件数据对比)。
本文设计的模块即实现了数据 → AXI Stream 输出 的转换。
————————————————————————————————————
C++程序:
C++程序用于产生存储数据的.bin文件,文件中第一个32bit数据为文件中全部有效数据的总字节数,其后的数据为按顺序排列的有效数据。
#include <iostream>
using namespace std;
#define N 32
int main()
{
/* write file */
FILE* fp;
unsigned int byte_cnt=0;
unsigned int data[N];//sizeof(unsigned int) == 4 bytes
fp = fopen("test_axis.bin", "wb");
fseek(fp, sizeof(byte_cnt), SEEK_CUR);//指针从当前位置向后移动 sizeof(byte_cnt) 个字节 ,留作之后再写入
for(int i=0;i<N;i++)
{
data[i] = i;
}
fwrite(data, sizeof(unsigned int), N, fp);
byte_cnt += N * sizeof(unsigned int);
cout<<byte_cnt<<" bytes have been written in file."<<endl;
fwrite(data, sizeof(unsigned int), N, fp);
byte_cnt += N * sizeof(unsigned int);
cout<<byte_cnt<<" bytes have been written in file."<<endl;
//向前移动会把前面的数据覆盖
fseek(fp, -(byte_cnt + sizeof(byte_cnt)), SEEK_CUR);//指针从当前位置向前移动 (byte_cnt + sizeof(byte_cnt)) 个字节
fwrite(&byte_cnt, sizeof(byte_cnt), 1, fp);//在前面写入总共的字节数,此时,指针从当前位置向后移动 sizeof(byte_cnt) 个字节
fseek(fp, (byte_cnt + sizeof(int)), SEEK_CUR);//指针还原
byte_cnt = 0;
fclose(fp);
/* read file */
FILE* fp_r;
unsigned int rd_data[N*2+1];//sizeof(unsigned int) == 4 bytes
fp_r = fopen("test_axis.bin", "rb");
fread(rd_data, sizeof(unsigned int) , N*2+1, fp_r);
fclose(fp_r);
printf("\n");
for(int i=0;i<N*2+1;i++)
{
printf("rd_data[%d] = %d\n", i, rd_data[i]);
}
printf("\n");
return 0;
}
vip程序:
`timescale 1ns / 1ns
//
// Company:
// Engineer:
//
// Create Date: 11/09/2020
// Author Name: Sniper
// Module Name: axis_driver
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module axis_driver
#(
parameter WIDTH = 32
)
(
input clk,
input rst_n,
input start,
output reg m_axis_tvalid,
input m_axis_tready,
output reg [WIDTH-1:0] m_axis_tdata,
output reg m_axis_tlast,
input [16*8-1:0] id,
input [128*8-1:0] filename
);
integer file;
reg [7:0] state;
reg [31:0] transfer_byte_cnt;
reg [31:0] sum_byte_num;
reg [WIDTH-1:0] file_data;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= 0;
transfer_byte_cnt <= 0;
m_axis_tvalid <= 0;
m_axis_tlast <= 0;
m_axis_tdata <= 0;
end
else
begin
case(state)
0://init
begin
file = $fopen(filename,"rb");
state <= state + 1;
if(!file)
$error("Failed to open %s",filename);
end
1://wait for start pulse
begin
if(start)//start==1 only 1 clk period
begin
$fread(sum_byte_num,file);//first 32bit data is sum_byte_num
sum_byte_num = {<<8{sum_byte_num}};//convert the sequence of byte
$fread(file_data,file);
file_data = {<<8{file_data}};
m_axis_tdata <= file_data;
transfer_byte_cnt <= transfer_byte_cnt + (WIDTH/8);
m_axis_tvalid <= 1;
state <= state + 1;
end
end
2://transfer
begin
if(m_axis_tvalid & m_axis_tready)//handshake
begin
$fread(file_data,file);
file_data = {<<8{file_data}};
m_axis_tdata <= file_data;
transfer_byte_cnt <= transfer_byte_cnt + (WIDTH/8);
m_axis_tvalid <= 1;
if(transfer_byte_cnt == sum_byte_num - (WIDTH/8))
begin
m_axis_tlast <= 1;
state <= state + 1;
end
end
end
3://reset
begin
m_axis_tvalid <= 0;
m_axis_tlast <= 0;
m_axis_tdata <= 0;
$fclose(file);
sum_byte_num = 0;
transfer_byte_cnt <= 0;
state <= 0;
end
endcase
end
end
endmodule
vip_tb:
`timescale 1ns / 1ns
//
// Company:
// Engineer:
//
// Create Date: 11/09/2020
// Author Name: Sniper
// Module Name: tb_axis_driver
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_axis_driver;
//parameter
parameter WIDTH = 32;
//input
reg clk;
reg rst_n;
reg start;
reg m_axis_tready;
reg [16*8-1:0] id;
reg [128*8-1:0] filename;
//output
wire m_axis_tvalid;
wire [WIDTH-1:0] m_axis_tdata;
wire m_axis_tlast;
initial
begin
clk = 0;
rst_n = 0;
start = 0;
m_axis_tready = 1;
id[16*8-1:0] = "AXIS_DRIVER_0";
filename[128*8-1:0] = "test_axis.bin";
#100;
rst_n = 1;
#100;
@(posedge clk)
start <= 1;
@(posedge clk)
start <= 0;
#1000;
@(posedge clk)
start <= 1;
@(posedge clk)
start <= 0;
#1000;
@(posedge clk)
start <= 1;
@(posedge clk)
start <= 0;
end
//clock
always #5 clk = ~clk;
//DUT
axis_driver
#(
.WIDTH(WIDTH)
)
DUT
(
.clk(clk),
.rst_n(rst_n),
.start(start),
.m_axis_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
.m_axis_tdata(m_axis_tdata),
.m_axis_tlast(m_axis_tlast),
.id(id),
.filename(filename)
);
initial
begin
$dumpfile("curve.vcd");
$dumpvars(0,DUT);
end
initial #10000 $finish;
endmodule