test case
2026/9/8 15:27:40 网站建设 项目流程

可以先用virtual sequence

class ahb_basic_vseq extends uvm_sequence; `uvm_object_utils(ahb_basic_vseq) ahb_sequencer seqr; function new(string name="ahb_basic_vseq"); super.new(name); endfunction virtual task body(); ahb_single_write_seq wr_seq; ahb_single_read_seq rd_seq; wr_seq = ahb_single_write_seq::type_id::create("wr_seq"); rd_seq = ahb_single_read_seq::type_id::create("rd_seq"); wr_seq.start(seqr); rd_seq.start(seqr); endtask endclass

test:

virtual task run_phase(uvm_phase phase); ahb_basic_vseq vseq; phase.raise_objection(this); vseq = ahb_basic_vseq::type_id::create("vseq"); vseq.seqr = env.ahb_agent.seqr; vseq.start(null); phase.drop_objection(this); endtask
seq/ ├── ahb_base_sequence.sv ├── ahb_single_write_seq.sv ├── ahb_single_read_seq.sv ├── ahb_incr_seq.sv ├── ahb_wrap4_seq.sv ├── ahb_error_seq.sv └── virtual/ ├── ahb_smoke_vseq.sv ├── ahb_single_vseq.sv ├── ahb_burst_vseq.sv └── ahb_random_vseq.sv test/ ├── ahb_base_test.sv ├── ahb_smoke_test.sv ├── ahb_single_test.sv ├── ahb_burst_test.sv ├── ahb_error_test.sv └── ahb_random_test.sv

vseqr自己不真正向 driver 发 transaction,主要用于保存多个真实 sequencer 的句柄。

例如:

class ahb_virtual_sequencer extends uvm_sequencer; `uvm_component_utils(ahb_virtual_sequencer) ahb_sequencer ahb_seqr; other_sequencer other_seqr; endclass

然后 virtual sequence:

class xxx_vseq extends uvm_sequence; `uvm_object_utils(xxx_vseq) `uvm_declare_p_sequencer(ahb_virtual_sequencer) virtual task body(); ahb_seq.start(p_sequencer.ahb_seqr); other_seq.start(p_sequencer.other_seqr); endtask endclass

这在多个接口的时候特别有意义,比如:

DUT AHB master agent ---> ahb_seqr APB agent ---> apb_seqr interrupt agent ---> irq_seqr
Seq主要负责
ahb_single_rw_seqSINGLE 基本读写、write→read、8/16/32bit、不同 offset
ahb_incr_seqINCR burst,读写、不同长度、不同 size
ahb_wrap4_seqWRAP4 读写、地址回绕、size
ahb_pipeline_seq连续传输 RR/RW/WR/WW、同地址/不同地址、2/3/10/30/50 笔
ahb_busy_seqburst 中插 BUSY、不同 BUSY 位置
ahb_error_seq越界、single 跨 1KB、WRAP4 未对齐等 error
ahb_random_seq前面条件随机组合,用来冲 coverage

ahb_single_rw_seq

virtual task body(); bit [31:0] data_q[$]; burst = AHB_SINGLE; size = AHB_WORD; start_addr = 32'h0000_1000; data_q.push_back(32'h1234_5678); ahb_write(data_q); ahb_read(); endtask

没问题之后

`ifndef AHB_SINGLE_RW_SEQ_SV `define AHB_SINGLE_RW_SEQ_SV class ahb_single_rw_seq extends ahb_base_sequence; `uvm_object_utils(ahb_single_rw_seq) function new(string name = "ahb_single_rw_seq"); super.new(name); endfunction // SINGLE write -> read same address virtual task single_rw( input bit [31:0] addr, input ahb_size_e trans_size, input bit [31:0] data ); bit [31:0] data_q[$]; start_addr = addr; size = trans_size; data_q.push_back(data); ahb_write(data_q); ahb_read(); endtask virtual task body(); burst = AHB_SINGLE; // WORD single_rw(32'h0000_1000, AHB_WORD, 32'h1234_5678); // HALFWORD: two legal offsets single_rw(32'h0000_1010, AHB_HALFWORD, 32'h0000_ABCD); single_rw(32'h0000_1012, AHB_HALFWORD, 32'h0000_1357); // BYTE: four legal offsets single_rw(32'h0000_1020, AHB_BYTE, 32'h0000_0011); single_rw(32'h0000_1021, AHB_BYTE, 32'h0000_0022); single_rw(32'h0000_1022, AHB_BYTE, 32'h0000_0033); single_rw(32'h0000_1023, AHB_BYTE, 32'h0000_0044); endtask endclass `endif

之后也可以随机

`ifndef AHB_SINGLE_RW_SEQ_SV `define AHB_SINGLE_RW_SEQ_SV class ahb_single_rw_seq extends ahb_base_sequence; `uvm_object_utils(ahb_single_rw_seq) function new(string name = "ahb_single_rw_seq"); super.new(name); endfunction // SINGLE write -> read same address virtual task single_rw( input bit [31:0] addr, input ahb_size_e trans_size, input bit [31:0] data ); bit [31:0] data_q[$]; start_addr = addr; size = trans_size; data_q.push_back(data); ahb_write(data_q); ahb_read(); endtask // Generate random valid data according to transfer size virtual task single_rw_random( input bit [31:0] addr, input ahb_size_e trans_size ); bit [31:0] data; case(trans_size) AHB_BYTE: data = $urandom_range(8'hFF, 0); AHB_HALFWORD: data = $urandom_range(16'hFFFF, 0); AHB_WORD: data = $urandom; default: data = '0; endcase `uvm_info("AHB_SINGLE_RW_SEQ", $sformatf("addr=%08h size=%s data=%08h", addr, trans_size.name(), data), UVM_MEDIUM) single_rw(addr, trans_size, data); endtask virtual task body(); burst = AHB_SINGLE; // WORD single_rw_random(32'h0000_0000, AHB_WORD); // HALFWORD: legal offset 0/2 single_rw_random(32'h0000_0010, AHB_HALFWORD); single_rw_random(32'h0000_0012, AHB_HALFWORD); // BYTE: legal offset 0/1/2/3 single_rw_random(32'h0000_0020, AHB_BYTE); single_rw_random(32'h0000_0021, AHB_BYTE); single_rw_random(32'h0000_0022, AHB_BYTE); single_rw_random(32'h0000_0023, AHB_BYTE); endtask endclass `endif

incr

`ifndef AHB_INCR_SEQ_SV `define AHB_INCR_SEQ_SV class ahb_incr_seq extends ahb_base_sequence; `uvm_object_utils(ahb_incr_seq) function new(string name = "ahb_incr_seq"); super.new(name); endfunction // INCR write -> read virtual task incr_rw( input bit [31:0] addr, input ahb_size_e trans_size, input int unsigned beats ); bit [31:0] data_q[$]; bit [31:0] data; start_addr = addr; size = trans_size; for(int unsigned i = 0; i < beats; i++) begin case(trans_size) AHB_BYTE: data = $urandom_range(8'hFF, 0); AHB_HALFWORD: data = $urandom_range(16'hFFFF, 0); AHB_WORD: data = $urandom; default: `uvm_fatal("AHB_INCR_SEQ", "Illegal transfer size") endcase data_q.push_back(data); end ahb_write(data_q, beats); ahb_read(beats); endtask virtual task body(); burst = AHB_INCR; // BYTE: 4 beats -> 0x040~0x043 incr_rw(32'h0000_0040, AHB_BYTE, 4); // HALFWORD: 4 beats -> 0x080/82/84/86 incr_rw(32'h0000_0080, AHB_HALFWORD, 4); // WORD: 4 beats -> 0x0C0/C4/C8/CC incr_rw(32'h0000_00C0, AHB_WORD, 4); endtask endclass `endif

对应 testcase:

`ifndef AHB_INCR_TEST_SV `define AHB_INCR_TEST_SV class ahb_incr_test extends ahb_base_test; `uvm_component_utils(ahb_incr_test) function new(string name = "ahb_incr_test", uvm_component parent = null); super.new(name, parent); endfunction virtual task run_phase(uvm_phase phase); ahb_incr_seq seq; phase.raise_objection(this); seq = ahb_incr_seq::type_id::create("seq"); seq.start(env.ahb_agent.seqr); phase.drop_objection(this); endtask endclass `endif
适合挪到 base_sequence 里,做成:
virtual function automatic bit [31:0] get_random_data( input ahb_size_e size_type ); case(size_type) AHB_BYTE: return $urandom_range(8'hFF, 0); AHB_HALFWORD: return $urandom_range(16'hFFFF, 0); AHB_WORD: return $urandom; default: return '0; endcase endfunction

那 INCR 里面直接:

for(int unsigned i = 0; i < beats; i++) data_q.push_back(get_random_data(trans_size));

single_rw_seq也可以改成:

data = get_random_data(trans_size);

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询