Start sequence after one completes or hold off if one is active

Trying to figure out how to properly set up two sequences which have the following relationship. There is a update_regs task which starts a RAM sequence that is a series of write AXI transactions to a RAM. There is a set_default_seq(phase) which starts a video sequence. However, the update_regs task itself repeats for a number of defined frames and calls the RAM sequence again at the end of a frame.

What is happening in sim is that initially the video sequence is starting before the AXI write transaction sequence is complete. Can I use uvm_event to better control this or is there an alternative method? I’d like to say "Don’t start the video sequence until the AXI write sequence is complete.

task base_test_c::run_phase(uvm_phase phase);
  `uvm_info(get_type_name(),"RUNNING",UVM_LOW)

  phase.raise_objection(this);
  `uvm_info(name, "raise objection in base test", UVM_MEDIUM)
  fork
    set_video_seq(phase);
    write_regs();
    begin
      wait (!top.u_dut.rst);
      `uvm_info(name, "Reset Released!!", UVM_MEDIUM)
     OTHER CODE IS HERE......
    end
  join
  `uvm_info(name, "drop objection in base test", UVM_MEDIUM)
  phase.drop_objection(this);

endtask : run_phase

In reply to solosys:

You are starting your sequences in a fork/join, i.e. 2 sequences an 3rd code part are running in parallel. Which task is picked first is randomly but repeatable.
It could be the write_regs is starting first. Is thid the behavior you want to see?

In reply to chr_sue:

The write_regs is indeed starting first per my DVE capture. That is desired. What’t not desired is that the video sequence to start before the 1st write_regs is complete. Each subsequent write_regs is probably ok because it runs at the end of a frame and there is plenty of time to update all of the regs before the start of the next frame. This wasn’t an issue before when there were only a few registers to update so the write_regs always finished in time before the video sequence started.

It seems like what I would like is for the video sequence to be delayed until the write_regs(); is finished.

task base_test_c::update_regs();
  cur_frame = cfg_h.start_on_frame;
  init_interlace();
  repeat (cfg_h.num_frames) begin : P_update_regs
    `uvm_info(name,$sformatf("Updating Control Registers"),UVM_MEDIUM);
     
    code for setting register values is here....
     
    //Write to regs (creates AXI wr trns)
    write_regs();

    @(cfg_h.video_cfg_h.driver_end_of_frame) cur_frame++;    

    
      //wait until start of next frame before changing registers
      //assuming all processing is done during 1 frame time
    
    
    @(cfg_h.video_cfg_h.driver_start_of_frame);

  end : P_update_regs
endtask : update_regs

can you show us code for these two methods?

set_video_seq(phase);
write_regs();

just to get a better understanding of how they are starting the respective sequences.

yes, uvm_event is a good way to synchronize this task and you can use uvm_event_pool::get_global(“<event_name>”) to get the singleton event in both the sequences.

In reply to solosys:

You don’t want video_sequence to be started before write_regs seq, right? Then why dont you execute them sequentially. Dont fork them to 2 parallel threads. Like:


fork
begin 
  write_regs()
  set_video_seq()
end
begin
  // other codes
end
join

I assume write_regs is blocking execute.

In reply to sohan_b:

It’s sanitized a little bit but here is the general content.

task base_test_c::set_video_seq(uvm_phase phase);
  phase.raise_objection(this);
  `uvm_info(name, "raise objection", UVM_MEDIUM)

  seq_h = video_seq_c::type_id::create("video_seq", this);
  seq_h.start(tb_env_h.env_h.video_in_env_h.agent_h.sequencer_h);
           
  `uvm_info(name, "drop objection", UVM_MEDIUM)
    phase.drop_objection(this);
endtask : set_video_seq
task base_test_c::write_regs();
  write_seq_c           write_seq_h;
  int                   mem_array []; 

  mem_array = new[axi_reg_pkg::REG_SIZE_W32];
  foreach (reg.w32[i]) mem_array[i] = reg.w32[i];
  `uvm_info(name,$sformatf("\n%p",reg.id),UVM_NONE);
  
  write_seq_h = write_seq_c::type_id::create("write_reg_seq");
  write_seq_h.set_start_addr(0);
  write_seq_h.set_array_by_ref(mem_array);
  write_seq_h.start(tb_env_h.ram_env_h.agent_h[0].sequencer_h);
endtask : write_regs

In reply to chris_le:

I think the problem there is that write_regs will never quit because the task repeats every frame, so the video sequence needs to be running as well.

In reply to Shipra_s:

How long that you need to wait? I dont think it is a good approach.
Instead, you can use uvm_event to manage these sequences.

Once more thing, you dont need to use raise/drop objection because in run phase, you already have it with fork, join.

In reply to chris_le:

Why do you think it’s not a good approach?

If uvm_event will be used then also there will be a wait period till that event gets triggered, that amount of wait period can be directly used here, here there’re only two threads write_regs and video_seq that needs to be synchronized and only at the beginning i.e, before the start of video_seq and no other processes dependency on these two , so inspite of using uvm_event directly wait/delay before the start of video_seq can also be used.

In reply to Shipra_s:

I think what’s confusing the matter is I incorrectly typed my run_phase initially.

There are three tasks: update_regs(), which calls a function write_regs(), which starts a sequence, write_seq. set_video_seq, once spawned can run for x amount of frames. At the end of every frame, update_reqs() occurs, which then starts another write_seq.

task base_test_c::run_phase(uvm_phase phase);
  `uvm_info(get_type_name(),"RUNNING",UVM_LOW)
 
  phase.raise_objection(this);
  `uvm_info(name, "raise objection in base test", UVM_MEDIUM)
  fork
    set_video_seq(phase);
    update_regs();
    begin
      wait (!top.u_dut.rst);
     OTHER CODE IS HERE......
    end
  join
  `uvm_info(name, "drop objection in base test", UVM_MEDIUM)
  phase.drop_objection(this);
 
endtask : run_phase
task base_test_c::set_video_seq(uvm_phase phase);
  phase.raise_objection(this);
  `uvm_info(name, "raise objection", UVM_MEDIUM)
 
  seq_h = video_seq_c::type_id::create("video_seq", this);
  seq_h.start(tb_env_h.env_h.video_in_env_h.agent_h.sequencer_h);
 
  `uvm_info(name, "drop objection", UVM_MEDIUM)
    phase.drop_objection(this);
endtask : set_video_seq
task base_test_c::write_regs();
  write_seq_c           write_seq_h;
  int                   mem_array []; 
 
  mem_array = new[axi_reg_pkg::REG_SIZE_W32];
  foreach (reg.w32[i]) mem_array[i] = reg.w32[i];
  `uvm_info(name,$sformatf("\n%p",reg.id),UVM_NONE);
 
  write_seq_h = write_seq_c::type_id::create("write_reg_seq");
  write_seq_h.set_start_addr(0);
  write_seq_h.set_array_by_ref(mem_array);
  write_seq_h.start(tb_env_h.ram_env_h.agent_h[0].sequencer_h);
endtask : write_regs

What was not included before is update_regs(). Here is a simplified version of it.

//------------------------------------------------------------------------ 
//Update registers every frame
//------------------------------------------------------------------------ 
task base_test_c::update_regs();
  cur_frame = proc_cfg_h.start_on_frame;
  repeat (proc_cfg_h.num_frames) begin : P_update_regs

    
  reg_bank.id.r.s.reg1        = '{ bypass   : 1'b0
                                 , value    : 5'd30
                                 , default  : '0
                                 };
  reg_bank.id.r.s.reg2        = '{ bypass   : 1'b0
                                 , value    : 5'd40
                                 , default  : '0
                                 };                                                                                               
    `uvm_info(name,$sformatf("Updating Registers"),UVM_MEDIUM);       
    write_regs();

    @(proc_cfg_h.in_video_bus_cfg_h.driver_end_of_frame) cur_frame++;    
    
      //wait until start of next frame before changing registers
      //assuming all processing is done during 1 frame time

    @(proc_cfg_h.in_video_bus_cfg_h.driver_start_of_frame);
  end : P_update_regs
endtask : update_regs

I would attach waveforms but can’t figure out how