15. 示例:创建AXI-Lite事务类(addr/data/rw)
文章目录
- 前言
- 示例一: AXI-Lite事务类
- 1. xrun仿真指令
- 2. 代码解析
- 3. 常见误区与解决方法
- 4. 应用场景扩展
- 示例二:AXI-Lite事务类实现
- 1. AXI-Lite事务类实现(SystemVerilog)
- 2. 测试平台示例
- 3. xSim仿真指令
- 4. 关键实现说明:
- 示例三:AXI-Lite事务类实现与仿真示例
- 1. AXI-Lite事务类定义
- 2. Driver与Monitor实现
- 3. 仿真环境与测试用例
- 4. xrun仿真指令
- 5. 关键实现说明
- 示例四: AXI-Lite事务类
- 1. AXI-Lite事务类定义(`axi_lite_transaction.sv`)
- 2. 测试平台示例(`axi_lite_tb.sv`)
- 3. xrun仿真指令
- 4. 关键设计点说明
- 5. 示例输出
前言
以下是一个完整的SystemVerilog示例,实现AXI-Lite事务类(包含地址、数据和读写类型),并提供xrun仿真指令:
示例一: AXI-Lite事务类
// ======================= AXI-Lite事务类定义 =======================
class axi_lite_transaction;
// 枚举类型定义读写操作
typedef enum {READ, WRITE} rw_type;
// 随机化字段
rand bit [31:0] addr; // 32位地址
rand bit [31:0] data; // 32位数据
rand rw_type rw; // 读/写操作
// 地址对齐约束(AXI-Lite要求地址按数据宽度对齐)
constraint addr_alignment {
addr % 4 == 0; // 4字节对齐
}
// 数据范围约束
constraint data_range {
data inside {[0:32'hFFFF_FFFF]};
}
// 读写操作分布约束
constraint rw_dist {
rw dist {READ := 40, WRITE := 60}; // 60%写操作,40%读操作
}
// 打印事务内容
function void print();
string operation;
operation = (rw == WRITE) ? "WRITE" : "READ";
$display("[AXI-Lite] %s @ 0x%08h : 0x%08h",
operation, addr, data);
endfunction
// 将事务打包为字节数组(用于驱动信号)
function byte unsigned[] pack();
byte unsigned bytes[];
bytes = new[8]; // 4字节地址 + 4字节数据
{>>{bytes}} = {<<byte{addr, data}}; // 小端序打包
return bytes;
endfunction
endclass
// ======================= 测试平台 =======================
module tb;
axi_lite_transaction tr;
initial begin
tr = new(); // 创建事务对象
$display("========== AXI-Lite事务测试 ==========");
repeat(5) begin
// 随机化事务
if (!tr.randomize()) begin
$error("Randomization failed!");
$finish;
end
// 打印事务内容
tr.print();
// 打包并显示字节流
begin
byte unsigned packet[];
packet = tr.pack();
$write("Packet Bytes: ");
foreach(packet[i]) $write("%02h ", packet[i]);
$display("\n");
end
#10; // 模拟时间推进
end
$display("========== 测试完成 ==========");
$finish;
end
endmodule
1. xrun仿真指令
xrun -sv -64bit -access +rw axi_lite_tb.sv
仿真输出示例:
========== AXI-Lite事务测试 ==========
[AXI-Lite] WRITE @ 0x00001230 : 0x89abcdef
Packet Bytes: 30 12 00 00 ef cd ab 89
[AXI-Lite] READ @ 0x0000fffc : 0x12345678
Packet Bytes: fc ff 00 00 78 56 34 12
[AXI-Lite] WRITE @ 0x00003c00 : 0xdeadbeef
Packet Bytes: 00 3c 00 00 ef be ad de
[AXI-Lite] READ @ 0x00002400 : 0x55aa55aa
Packet Bytes: 00 24 00 00 aa 55 aa 55
[AXI-Lite] WRITE @ 0x00001800 : 0x11223344
Packet Bytes: 00 18 00 00 44 33 22 11
========== 测试完成 ==========
2. 代码解析
-
事务类结构:
addr
:32位对齐地址(addr % 4 == 0
)data
:32位数据rw
:读写类型枚举(READ/WRITE)
-
约束特性:
- 地址必须4字节对齐(AXI-Lite协议要求)
- 数据范围覆盖全32位
- 读写操作加权分布(60%写操作)
-
实用方法:
print()
:格式化打印事务内容pack()
:将地址和数据打包为小端字节序
-
测试平台:
- 生成5个随机事务
- 显示事务内容和打包后的字节流
3. 常见误区与解决方法
-
地址未对齐错误:
- 现象:协议违反导致DUT错误
- 解决:确保约束
addr % 4 == 0
-
枚举类型未正确使用:
// 错误写法
tr.rw = 1;
// 正确写法
tr.rw = axi_lite_transaction::WRITE;
- 内存泄漏:
- 现象:重复new()未释放
- 解决:使用
automatic
存储类或显式销毁对象
automatic axi_lite_transaction tr = new();
4. 应用场景扩展
-
验证场景:
- 正常操作:读写寄存器验证
- 边界测试:地址=0x00000000/0xFFFFFFFC
- 错误注入:临时关闭约束测试协议错误
-
功能覆盖:
covergroup axi_cov;
addr_range: coverpoint tr.addr {
bins low = {[0:32'h0000_FFFF]};
bins mid = {[32'h0001_0000:32'hFFFF_0000]};
bins high = {[32'hFFFF_0001:32'hFFFF_FFFF]};
}
rw_type: coverpoint tr.rw;
endgroup
通过这个示例,您可以快速上手AXI-Lite事务建模,并基于此扩展构建完整的验证环境。
示例二:AXI-Lite事务类实现
1. AXI-Lite事务类实现(SystemVerilog)
// 定义AXI-Lite事务类
class axi_lite_transaction;
// 地址/数据位宽(默认32位)
rand logic [31:0] addr;
rand logic [31:0] data;
rand enum { READ, WRITE } rw;
// 地址对齐约束(4字节对齐)
constraint addr_alignment {
addr[1:0] == 2'b00; // AXI-Lite要求地址按4字节对齐
}
// 数据范围约束(可选)
constraint data_range {
data inside {[0:32'hFFFF_FFFF]}; // 根据需求调整范围
}
// 读写操作比例约束(默认1:1)
constraint rw_ratio {
rw dist { READ := 50, WRITE := 50 };
}
// 打印事务内容
function void display();
$display("[%0t] AXI-Lite %s: addr=0x%8h, data=0x%8h",
$time, rw.name(), addr, data);
endfunction
endclass
2. 测试平台示例
module tb_axi_lite;
// AXI-Lite接口信号声明
logic aclk;
logic aresetn;
logic [31:0] awaddr;
logic awvalid;
logic awready;
logic [31:0] wdata;
logic wvalid;
logic wready;
// ...其他信号省略...
// 事务生成器
initial begin
axi_lite_transaction tr = new();
repeat(10) begin
assert(tr.randomize()); // 随机生成事务
tr.display();
case(tr.rw)
axi_lite_transaction::WRITE: drive_write(tr);
axi_lite_transaction::READ: drive_read(tr);
endcase
#10;
end
$finish;
end
// 写事务驱动任务
task drive_write(axi_lite_transaction tr);
// 驱动写地址通道
awaddr = tr.addr;
awvalid = 1'b1;
@(posedge aclk iff awready);
awvalid = 1'b0;
// 驱动写数据通道
wdata = tr.data;
wvalid = 1'b1;
@(posedge aclk iff wready);
wvalid = 1'b0;
endtask
// 读事务驱动任务(类似实现)
// ...省略...
endmodule
3. xSim仿真指令
# 编译命令
xrun -sv \
-access +rwc \
-incdir ./include \
-define AXI_DATA_WIDTH=32 \
axi_lite_transaction.sv \
tb_axi_lite.sv \
axi_lite_slave_model.sv
# 仿真运行(带波形输出)
xrun -input waves.tcl \
-coverage all \
-uvmhome $UVM_HOME # 若集成UVM可添加
4. 关键实现说明:
-
事务类设计
- 使用
rand
修饰符实现随机化生成 - 通过约束保证地址对齐(AXI-Lite强制要求)
- 内置显示函数用于调试跟踪
- 使用
-
接口驱动
- 采用任务(task)分离读写操作流程
- 基于握手信号(valid/ready)实现协议时序
-
仿真配置
-access +rwc
启用信号访问跟踪-coverage all
启用功能覆盖率收集- 可搭配波形文件(waves.tcl)进行可视化调试
示例三:AXI-Lite事务类实现与仿真示例
1. AXI-Lite事务类定义
// 定义事务类(继承uvm_sequence_item)
class axi_lite_transaction extends uvm_sequence_item;
// 字段定义
rand logic [31:0] addr; // 32位地址(对齐到4字节):ml-citation{ref="2,4" data="citationList"}
rand logic [31:0] data; // 32位数据:ml-citation{ref="2,4" data="citationList"}
rand enum {READ, WRITE} rw; // 读写方向:ml-citation{ref="2,4" data="citationList"}
// 约束条件
constraint addr_alignment { addr[1:0] == 0; } // AXI-Lite地址对齐规则:ml-citation{ref="2,4" data="citationList"}
constraint data_range { data inside {[0:32'hFFFF_FFFF]}; }
constraint rw_dist { rw dist { READ := 30, WRITE := 70 }; } // 操作类型分布:ml-citation{ref="3,4" data="citationList"}
// UVM自动化注册
`uvm_object_utils_begin(axi_lite_transaction)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_enum(enum {READ, WRITE}, rw, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "axi_lite_transaction");
super.new(name);
endfunction
endclass
2. Driver与Monitor实现
// Driver类(驱动AXI-Lite信号)
class axi_lite_driver extends uvm_driver #(axi_lite_transaction);
virtual axi_lite_if vif; // 虚拟接口:ml-citation{ref="3,4" data="citationList"}
`uvm_component_utils(axi_lite_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); // 获取事务:ml-citation{ref="3,4" data="citationList"}
drive_transaction(req);
seq_item_port.item_done();
end
endtask
task drive_transaction(axi_lite_transaction tr);
// 写操作驱动逻辑:ml-citation{ref="1,4" data="citationList"}
if (tr.rw == WRITE) begin
vif.awaddr <= tr.addr;
vif.awvalid <= 1;
vif.wdata <= tr.data;
vif.wvalid <= 1;
@(posedge vif.clk iff vif.awready && vif.wready); // 握手等待:ml-citation{ref="2,3" data="citationList"}
vif.awvalid <= 0;
vif.wvalid <= 0;
@(posedge vif.clk iff vif.bvalid); // 写响应等待:ml-citation{ref="2,3" data="citationList"}
end
// 读操作驱动逻辑:ml-citation{ref="1,4" data="citationList"}
else begin
vif.araddr <= tr.addr;
vif.arvalid <= 1;
@(posedge vif.clk iff vif.arready); // 握手等待:ml-citation{ref="2,3" data="citationList"}
vif.arvalid <= 0;
@(posedge vif.clk iff vif.rvalid); // 读数据等待:ml-citation{ref="2,3" data="citationList"}
tr.data = vif.rdata;
end
endtask
endclass
// Monitor类(监听总线事务)
class axi_lite_monitor extends uvm_monitor;
virtual axi_lite_if vif;
uvm_analysis_port #(axi_lite_transaction) ap; // 事务分析端口:ml-citation{ref="3,4" data="citationList"}
`uvm_component_utils(axi_lite_monitor)
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
task run_phase(uvm_phase phase);
forever begin
axi_lite_transaction tr;
// 捕获写事务:ml-citation{ref="2,3" data="citationList"}
if (vif.awvalid && vif.awready) begin
tr = axi_lite_transaction::type_id::create("tr");
tr.addr = vif.awaddr;
tr.rw = WRITE;
@(posedge vif.clk iff vif.wvalid && vif.wready);
tr.data = vif.wdata;
ap.write(tr);
end
// 捕获读事务:ml-citation{ref="2,3" data="citationList"}
if (vif.arvalid && vif.arready) begin
tr = axi_lite_transaction::type_id::create("tr");
tr.addr = vif.araddr;
tr.rw = READ;
@(posedge vif.clk iff vif.rvalid);
tr.data = vif.rdata;
ap.write(tr);
end
@(posedge vif.clk);
end
endtask
endclass
3. 仿真环境与测试用例
// 测试环境(集成Driver/Monitor)
class axi_lite_env extends uvm_env;
axi_lite_driver driver;
axi_lite_monitor monitor;
virtual axi_lite_if vif;
`uvm_component_utils(axi_lite_env)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = axi_lite_driver::type_id::create("driver", this);
monitor = axi_lite_monitor::type_id::create("monitor", this);
if (!uvm_config_db#(virtual axi_lite_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not set") // 接口配置检查:ml-citation{ref="3,4" data="citationList"}
driver.vif = vif;
monitor.vif = vif;
endfunction
endclass
// 测试用例(生成随机事务)
class axi_lite_test extends uvm_test;
axi_lite_env env;
`uvm_component_utils(axi_lite_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = axi_lite_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
axi_lite_transaction tr;
phase.raise_objection(this);
repeat(10) begin // 生成10个随机事务:ml-citation{ref="3,4" data="citationList"}
tr = axi_lite_transaction::type_id::create("tr");
assert(tr.randomize());
env.driver.seq_item_port.put(tr); // 发送到Driver:ml-citation{ref="3,4" data="citationList"}
end
phase.drop_objection(this);
endtask
endclass
4. xrun仿真指令
# 编译并仿真(使用Cadence Xcelium)
xrun -sv -64bit -access +rw \
axi_lite_pkg.sv \ # 事务类/接口定义
axi_lite_if.sv \ # 接口文件
axi_lite_driver.sv \ # Driver实现
axi_lite_monitor.sv \ # Monitor实现
axi_lite_env.sv \ # 环境集成
axi_lite_test.sv \ # 测试用例
top.sv \ # 顶层模块(连接DUT与TB)
-uvm -uvmhome CDNS-1.2 \
-wave \ # 生成波形
-timescale 1ns/1ps # 时间精度:ml-citation{ref="3,4" data="citationList"}
5. 关键实现说明
- 事务对齐约束:通过addr_alignment约束强制地址按4字节对齐,符合AXI-Lite协议要求。
- 握手协议实现:Driver中使用@(posedge vif.clk iff condition)等待VALID/READY握手完成。
- 覆盖率导向:通过rw_dist约束控制读写操作比例,提升验证效率。
- 接口绑定:使用uvm_config_db传递虚拟接口,实现TB与DUT连接。
示例四: AXI-Lite事务类
1. AXI-Lite事务类定义(axi_lite_transaction.sv
)
import uvm_pkg::*;
`include "uvm_macros.svh"
class axi_lite_transaction extends uvm_sequence_item;
// 定义字段
rand logic [31:0] addr; // 32位地址
rand logic [31:0] data; // 32位数据
rand enum {READ, WRITE} rw; // 读写类型
// 地址对齐约束(AXI-Lite要求地址按4字节对齐)
constraint addr_alignment {
addr % 4 == 0;
}
// UVM自动化注册
`uvm_object_utils_begin(axi_lite_transaction)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_enum(rw, UVM_ALL_ON)
`uvm_object_utils_end
// 构造函数
function new(string name = "axi_lite_transaction");
super.new(name);
endfunction
// 可选的copy函数
virtual function void do_copy(uvm_object rhs);
axi_lite_transaction rhs_;
if (!$$cast(rhs_, rhs)) begin
uvm_report_error("do_copy", "Copy failed");
return;
end
super.do_copy(rhs);
addr = rhs_.addr;
data = rhs_.data;
rw = rhs_.rw;
endfunction
endclass
2. 测试平台示例(axi_lite_tb.sv
)
module axi_lite_tb;
import uvm_pkg::*;
`include "uvm_macros.svh"
initial begin
axi_lite_transaction tr;
tr = axi_lite_transaction::type_id::create("tr");
// 生成并打印随机事务
repeat(5) begin
assert(tr.randomize());
$$display("[Transaction] Addr=0x%0h, Data=0x%0h, RW=%s",
tr.addr, tr.data, tr.rw.name());
end
$$finish;
end
endmodule
3. xrun仿真指令
执行以下命令编译并运行仿真:
xrun -uvm -access +rwc axi_lite_transaction.sv axi_lite_tb.sv
- 参数说明:
-uvm
: 启用UVM库支持。-access +rwc
: 允许对信号的读写权限。- 文件列表:包含事务类定义和测试平台文件。
4. 关键设计点说明
-
UVM集成:
- 事务类继承自
uvm_sequence_item
,支持UVM的随机化、序列化和调试功能。 - 使用
uvm_field_*
宏实现字段的自动化操作(如打印、复制等)。
- 事务类继承自
-
地址对齐约束:
- AXI-Lite协议要求地址按4字节对齐,通过约束
addr % 4 == 0
实现。
- AXI-Lite协议要求地址按4字节对齐,通过约束
-
随机化与测试:
- 在测试平台中调用
randomize()
生成随机事务,覆盖不同地址和数据组合。
- 在测试平台中调用
5. 示例输出
仿真运行后,控制台可能输出:
[Transaction] Addr=0x00001000, Data=0x12345678, RW=WRITE
[Transaction] Addr=0x00002004, Data=0xdeadbeef, RW=READ
...
通过此示例,可快速验证AXI-Lite事务类的功能,并扩展为完整的验证环境(如添加Driver/Monitor)。