Most important properties of a sequence are,
body method defines, what the sequence does.
The m_sequencer handle contains the reference to the sequencer on which the sequence is running.
The sequence will get executed upon calling the start of the sequence from the test.
sequence_name.start(sequencer_name);
sequencer_name specifies on which sequencer sequence has to run.
* mid_do and post_do are functions, All other are tasks
Logic to generate and send the sequence_item will be written inside the body() method of the sequence.
The handshake between the sequence, sequencer and driver to send the sequence_item is given below.
sequence driver communication
Communication between the Sequence and driver involves below steps,
1.create_item() / create req.
2.wait_for_grant().
3.randomize the req.
4.send the req.
5.wait for item done.
6.get response.
class mem_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(mem_sequence)
//Constructor
function new(string name = "mem_sequence");
super.new(name);
endfunction
virtual task body();
req = mem_seq_item::type_id::create("req"); //create the req (seq item)
wait_for_grant(); //wait for grant
assert(req.randomize()); //randomize the req
send_request(req); //send req to driver
wait_for_item_done(); //wait for item done from driver
get_response(rsp); //get response from driver
endtask
endclass
Note: assert(req.randomize());, will return the assertion error on randomization failure.
These macros are used to start sequences and sequence items on default sequencer, m_sequencer.
class mem_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(mem_sequence)
//Constructor
function new(string name = "mem_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_do(req)
endtask
endclass
class mem_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(mem_sequence)
//Constructor
function new(string name = "mem_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_create(req)
assert(req.randomize());
`uvm_send(req);
endtask
endclass
class mem_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(mem_sequence)
//Constructor
function new(string name = "mem_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_create(req)
`uvm_rand_send(req)
endtask
endclass
class write_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(write_sequence)
//Constructor
function new(string name = "write_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_do_with(req,{req.wr_en == 1;})
endtask
endclass
class read_sequence extends uvm_sequence#(mem_seq_item);
`uvm_object_utils(read_sequence)
//Constructor
function new(string name = "read_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_create(req)
`uvm_rand_send_with(req,{req.rd_en == 1;})
endtask
endclass
class wr_rd_seq extends uvm_sequence#(mem_seq_item);
write_sequence wr_seq;
read_sequence rd_seq;
`uvm_object_utils(wr_rd_seq)
//Constructor
function new(string name = "wr_rd_seq");
super.new(name);
endfunction
virtual task body();
`uvm_do(wr_seq)
`uvm_do(rd_seq)
endtask
endclass
The m_sequencer handle contains the reference to the sequencer(default sequencer) on which the sequence is running.
This is determined by,
The p_sequencer is a variable, used as a handle to access the sequencer properties.
p_sequencer is defined using the macro
`uvm_declare_p_sequencer(SEQUENCER_NAME)