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();
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
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