Help in finding better way to restructure the code

I have a logic where a semaphore waits for key only if a particular condition is not set and once I gather the key, I release after clocking block statement one cycle later. However, if a condition is set, therefore, it checks in next cycle for the key. I think my implementation in the code is too clumsy. The issue in this logic is that when we check for key every cycle, we might miss the key as the thread which releases the lock runs later and we get the lock in next cycle. Therefore, I need help re-structuring the code and the logic is shown below.

forever begin
  while(condition_set)
    @(cb);
  if(try_get())
    break;
  else
    @(cb);
end

//
drive some signals
//

@(cb);
put();

In reply to rahulkumarbudhwani:
See if this model provides some answers for you.
http://systemverilog.us/vf/sem.sv


module top;
    timeunit 1ns;  timeprecision 100ps;    
    `include "uvm_macros.svh"
    import uvm_pkg::*;
    bit clk, cond;
    semaphore smTx;
    event e1, e_other; 
    initial  smTx=new(1);
    default clocking @(posedge clk);
    endclocking
    initial forever #10 clk = !clk;


   /* I have a logic where a semaphore waits for key only if a particular condition is not set 
    and once I gather the key, I release after clocking block statement one cycle later. 
    However, if a condition is set, therefore, it checks in next cycle for the key. 
    I think my implementation in the code is too clumsy. 
    The issue in this logic is that when we check for key every cycle, 
    we might miss the key as the thread which releases the lock runs later 
    and we get the lock in next cycle. 
    Therefore, I need help re-structuring the code and the logic is shown below. */
    task automatic t1();	
        // If the specified number of keys is available, the method returns and execution continues. 
        // If the specified number of keys is not available, the process blocks until the keys become available.	 
        smTx.get(1); 
        $display("%t t1 got key", $time); 
        -> e1; 
           // drive some signals 
        @(posedge clk) smTx.put(1);
        $display("%t t1 PUT key", $time); 
	endtask

    task automatic t_other();
        smTx.get(1); 
        $display("%t t_other got key", $time); 
        -> e_other;
        #20;
           // drive some signals 
        @(posedge clk) smTx.put(1);
        $display("%t t1_other PUT key", $time); 
        
    endtask

    always @(posedge cond) begin 
       fork
           t1(); 
           t_other(); 
       join_any 
    end 
   
  
    initial begin
       bit[1:0] d; // delay
       bit c; // condition 
       realtime r;
      repeat (200) begin
        @(posedge clk);
        if (!randomize(c, d) with {
          c dist {1'b1 := 1, 1'b0 := 4};
        })
          `uvm_error("MYERR", "This is a randomize error");
         r= d*1ns; 
         #r; 
        cond <= c;
      end
      $finish;
    end
  endmodule

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact http://cvcblr.com/home.html
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats - SystemVerilog - Verification Academy
  2. Free books: Component Design by Example https://rb.gy/9tcbhl
    Real Chip Design and Verification Using Verilog and VHDL($3) https://rb.gy/cwy7nb
  3. Papers:

In reply to ben@SystemVerilog.us:

Hi Ben,
I do not see how this implements the priority as the events are only triggered but there is no wait condition on them. Is there anything I am missing?

In reply to rahulkumarbudhwani:
Rereading your initial requirements, I see this. I don’t see the need for the try_get, why can’t you use the **get.**The t1 task is initiated at every transition of cond. The t_other is triggered in my model by the same transition of cond, but that could be triggered by other conditions. I just made some assumptions here.
Anyway, the point I am bringing is that you can trigger a task upon changes in conditions. Note that these are automatic tasks, meaning that they are concurrent, and if cond toggles fast, it is possible to have multiples of these concurrent tasks running, with each asking for a get or put. Maybe not what you need. I am just providing discussions and options for you to consider.


module top;
    timeunit 1ns;  timeprecision 100ps;    
    `include "uvm_macros.svh"
    import uvm_pkg::*;
    bit clk, cond;
    semaphore smTx;
    event e1, e_other; 
    initial  smTx=new(1);
    default clocking @(posedge clk);
    endclocking
    initial forever #10 clk = !clk;


   /* I have a logic where a semaphore waits for key only if a particular condition is not set 
    and once I gather the key, I release after clocking block statement one cycle later. 
    However, if a condition is set, therefore, it checks in next cycle for the key. 
    I think my implementation in the code is too clumsy. 
    The issue in this logic is that when we check for key every cycle, 
    we might miss the key as the thread which releases the lock runs later 
    and we get the lock in next cycle. 
    Therefore, I need help re-structuring the code and the logic is shown below. */
    /*forever begin
      while(condition_set)
        @(cb);
      if(try_get())
        break;
      else
        @(cb);
    end*/

    task automatic t1();	
      // a semaphore waits for key only if a particular condition is not set 
      // and once I gather the key, I release after clocking block statement one cycle later. 
        if(!cond) begin 
           smTx.get(1); // blocks 
           $display("%t t1 got key", $time); 
          -> e1; 
          @(posedge clk) smTx.put(1);
          $display("%t t1 PUT key", $time); 
        end 
        else begin 
          // if a condition is set, therefore, it checks in next cycle for the key. 
          @(posedge clk);
          smTx.get(1); // blocks 
          $display("%t t1 got key", $time); 
           // drive some signals 
          @(posedge clk) smTx.put(1);
          $display("%t t1 PUT key", $time); 
        end
	endtask

    task automatic t_other(); // The other tasks not addressed by you 
        smTx.get(1); 
        $display("%t t_other got key", $time); 
        -> e_other;
        #20;
           // drive some signals 
        @(posedge clk) smTx.put(1);
        $display("%t t1_other PUT key", $time); 
        
    endtask

    always @(cond) begin 
       fork
           t1(); 
           t_other(); // for testbench
       join_any 
    end 
   
  
    initial begin
       bit[1:0] d; // delay
       bit c; // condition 
       realtime r;
      repeat (200) begin
        @(posedge clk);
        if (!randomize(c, d) with {
          c dist {1'b1 := 1, 1'b0 := 4};
        })
          `uvm_error("MYERR", "This is a randomize error");
         r= d*1ns; 
         #r; 
        cond <= c;
      end
      $finish;
    end
  endmodule