Interprocess communication#
Interprocess communication (IPC) is a set of programming interfaces that allow a programmer to coordinate activities among different program processes that can run concurrently in an operating system. This allows a program to handle many user requests at the same time
1-Events#
Event is used for synchronization between two or more concurrently active processes. Initially, we need to declare the event and then it needs to be triggered by using the -> or -» operator.
Processes can wait for the event by using the @ operator or wait(event_name.triggered). when both @ and wait comes at the same point then a race-around condition occurs in between both.
Create an event:-
event e;
Triggering the event:-
->e;
Wait for the event to be triggered:-
@e;
or
wait(e.triggered);
Difference between @ and wait operator:#
Generally both the @ and wait operators are used to waiting for an event to be triggered. The main difference between @ and wait is that when waiting of an event and triggering of an event takes place at same time then @ cannot detect the triggering where as wait can detect the triggering of the event and then executes .Lets see the difference between @ and wait with a code below .
code snippet:
module wait_example;
event e;
initial begin
$display($time,"\t triggering the event");
->e;
end
initial begin
$display($time,"\t waiting for the event using wait");
wait(e.triggered);
$display($time,"\t event is triggered using wait");
end
initial begin
$display($time,"\t waiting for the event using @");
@(e.triggered);
$display($time,"\t event is triggered using @");
end
endmodule
In the code triggering and waiting of an event takes place at same time at 0ns.wait will trigger the event whereas “@” cannot detect the triggering
code output:
In the output we can see that triggering and waiting of an event takes place at same time at 0ns then wait can detect the triggering so it displays the statement ’event is triggered using wait “where as @ cannot detect the triggering so the display statement below @ is not executed.
wait_order():#
wait_order() method is used to specify the events to be triggered in a particular order. It block the processes until all the events are triggered in the specified order.
syntax:
wait_order(event_1,event_2….event_n);
Example:
event e1;
event e2;
event e3;
wait_order(e1,e3,e2);
In the above example the events will get triggered in the order e1 then e3 and then e2 ,then only process gets executed otherwise it block the process. If we have specified the order and events are not executed in the order then run time error is generated. To avoid this error we can use else statement so we can get user message under else if events are not triggered in the order. Lets see with example
Example:wait_order(e1,e3,e2)
else display("events are out of order");
In this example, if events are not triggered in the given order a user message in else statement is displayed, instead of run time error being generated.
code snippet:
module wait_order;
event e1; //declaring event e1
event e2; //declaring event e2
event e3; //declaring event e3
initial begin
fork
//process-1, triggers the event e1
begin
#6;
$display($time,"\tTriggering The Event e3");
->e3;
end
//process-2, triggers the event e2
begin
#2;
$display($time,"\tTriggering The Event e1");
->e1;
end
//process-3, triggers the event e3
begin
#8;
$display($time,"\tTriggering The Event e2");
->e2;
end
//process-4, wait for the events to trigger in order of e1,e3 and e2
begin
$display($time,"\tWaiting for the Event's to trigger");
wait_order(e1,e3,e2)
$display($time,"\tEvent's triggered Inorder");
else
$display($time,"\tEvent's triggered Out-Of-Order");
end
join
end
endmodule
In the above code events e1,e2,e3 are declared, using wait_order we are specifying the events to be triggered in the order e1,e3,e2.so only if events are trigerred in the given order e1->,e3->,e2 then only the statement below wait_order executes otherwise else statement will execute.
code output:
Merging events#
In merging events one event variable is assigned to another variable then another event variable is also triggered at same time when first event is triggered due to merging. It means when second event variable is assigned to first event variable then second event variable waits and block the processes until the first event variable is triggered.
syntax:
event variable 1=event variable 2;
Example:
event a;
event b;
event b=a; // Merging events a and b
code snippet :
module merge_events;
event a,b;
initial begin
fork
#50 ->a;
#30 ->b;
#20 b = a;
begin
wait(a.triggered);
$display("[%0t] event a is done",$time);
end
begin
wait(b.triggered);
$display("[%0t] event b is done ",$time);
end
join
end
endmodule
In the above code events a,b are declared then a,b events are merged by b=a.
code output:
Blocking and Nonblocking events:#
Blocking event#
Generally blocking events are triggered using -> operator. Blocking events work in active region so when waiting of an event and triggering of an event takes place at same time then @ operator block the process still event is triggered so in this way -> operator block the events when waiting of an event and triggering of an event takes place at same time .But we can use wait operator to avoid this blocking.
syntax:
-> event name
Example:
event BJT;
-> BJT; // event triggered using blocking triggering//
code snippet:
module blocking_event;
event BJT;
initial begin
$display($time,"\t triggering the event");
->BJT;
end
initial begin
$display($time,"\t waiting for the event using wait");
wait(BJT.triggered);
$display($time,"\t event BJT is triggered using wait");
end
initial begin
$display($time,"\t waiting for the event using @");
@(BJT.triggered);
$display($time,"\t event BJT is triggered using @");
end
endmodule
code output:
As event BJT is declared using blocking triggering -> BJT.AS blocking triggering and @ both work in active region so when triggering and waiting of an event takes place at same time at 0ns by using @ operator it block the statement “event BJT is triggered using @”, below @(BJT.triggered)But we can use wait(BJT.triggered) to detect the triggering so it displays the statement “event BJT is triggered using @”.
Non blocking event#
Non blocking event is triggered using -» operator. As non blocking event triggering works in non blocking region and wait or @ works in active region so even though when waiting of an event and triggering of an event takes place at same time so @ does not blocks the process so –> is called as non blocking triggering. This is the difference between blocking and non blocking events.
syntax:
->>event name
Example:
event BJT;
->> BJT; // event triggered using non blocking triggering//
code snippet
module non_blocking;
event BJT;
initial begin
$display($time,"\t triggering the event");
->>BJT;
end
initial begin
$display($time,"\t waiting for the event using wait");
wait(BJT.triggered);
$display($time,"\t event BJT is triggered using wait");
end
initial begin
$display($time,"\t waiting for the event using @");
@(BJT.triggered);
$display($time,"\t event BJT is triggered using @");
end
endmodule
In the above code event BJT is declared using non blocking triggering -»BJT so even though when waiting of an event and triggering of an event takes place at same time so @ does not blocks the process as non blocking triggering works in non blocking region where @ works in active region so @ unblock the process below the @(BJT.triggered);
code ouput:
2-Semaphores#
Semaphore is a built-in class which is provided in the built-in std package of System Verilog. A semaphore allows you to control access to a resource. Conceptually, a semaphore is a bucket. When a semaphore is allocated, a bucket that contains a fixed number of keys is created. With help of semaphore method key can be gets or puts key into the bucket(semaphores).
In an analogy, semaphore can be understood as a bike rentals shop from where we can use bikes(keys) and the other person(thread/process) can only use the bikes if they are available. And they(thread/process) should wait till the previous bikes are returned.
Now we’ll see how to use semaphores in System Verilog.
Syntax:
semaphore semaphore_name;
Methods:#
Semaphore is a built-in class that provides the following methods:
I. new()
II. get()
III. put()
IV. try_get()
I-new() :#
This method is used to create a semaphore with particular number of keys.
Syntax:
semaphore_name=new(n);
Here, key count(i.e., n) is an integer. By default, n=0. If a semaphore is not created properly it returns null.
Key count is the value that is initially given to the semaphore. If wanted, one can also increase the keys in semaphore by putting more keys (using put() method) into semaphore than the removed number of keys.
II-get()#
get() is used to get specified number of keys from the semaphore.
Syntax:
semaphore_name.get(m);
By default, m=1.
If the keys are not available for a thread/process(i.e., if any other thread/process is using the keys of semaphore), it will wait till the keys get back to the semaphore and then executes it’s action.
III-put()#
This method is used to return it’s keys to the semaphore.
Syntax:
semaphore_name.put(k);
By default, k=1.
Example:
Below is the example of how to create a handle of semaphore and keys in it and how to get and put keys into the semaphore using the above mentioned methods.
Code snippet:
In the below example we try to find what would happen if a process returns only some of the keys it procured and put the remaining later.
module semaphore_example_1;
semaphore sem=new(6);
initial begin :BEGIN_I
$display("In first initial block At time=[%0t] ",$time);
sem.get(4);
$display("Thread 1:Accessing 4 keys from semaphore At time=[%0t] ",$time);
#5;
sem.put(4);
$display("Thread 1:Done using 4 keys At time=[%0t] ",$time);
end :BEGIN_I
initial begin :BEGIN_II
$display("In second initial block At time=[%0t] ",$time);
sem.get(2);
$display("Thread 2:Accessing 2 keys from semaphore At time=[%0t] ",$time);
#10;
sem.put(2);
$display("Thread 2:Done using 2 keys At time=[%0t] ",$time);
end :BEGIN_II
endmodule :semaphore_example_1
Output:
On above code we create 6 key. At a 0ns time in process-1 get 4 keys from semaphore and in process-2 get 2 keys.Then after time 5ns in process-1 we put 4 keys in semaphore and at time 10ns process-2 put 2 keys in semaphore.
Githhub logfile link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/production/Interprocess_communications/semaphore/sema_example1/sema_exm1.log
Example-2:
code snippet:
In below code we try to explain what happen if we try to get more key than the available key
module semaphore_exm_2;
semaphore sem=new(6);
initial begin :BEGIN_I
$display("In first initial block At time=[%0t]",$time);
sem.get(4);
$display("Thread 1:Accessing 4 keys from semaphore At time=[%0t]",$time);
#5;
sem.put(2);
$display("Thread 1:Done using 2 keys At time=[%0t]",$time);
#20;
$display("Thread 1:Still using the remaining 2 keys At time=[%0t]",$time);
end :BEGIN_I
initial begin :BEGIN_II
$display("In second initial block At time=[%0t]",$time);
sem.get(5);
$display("Thread 2:Accessing 5 keys from semaphore At time=[%0t]",$time);
#10;
sem.put(5);
$display("Thread 2:Done using 5 keys At time=[%0t]",$time);
end :BEGIN_II
endmodule :semaphore_exm_2
Output:
On above code we create 6 keys. At time 0ns process-1 get 4 keys from semaphore and process-2 try to get 5 key from semaphore but at a time only 2 keys are available so it block the next statement until 5 keys are available in semaphore. Then at 5ns time process-1 put 2 keys in semaphore and at time 4 keys are available in semaphore so process-2 again wait. At a 25ns time process-1 still using keys and process-1 is end but in semaphore only 4 keys are available so process-2 can not be execute.
IV-try_get()#
This method is also used to get specified number of keys from the semaphore. But unlike get() method, if keys are unavailable it will not wait and returns 0 and the next step executes.
Syntax:
semaphore_name.try_get(j);
By default, j=1.
If the specified number of keys are available, the method returns 1 and execution continues
If the specified number of keys are not available, the method returns 0 and execution continues
code snippet:
This code helps in understanding how to use try_get() method and what makes it different from get() method.
module semaphore_exa_get_try;
semaphore car_key = new(1);
initial begin :BEGIN_I
fork
begin :BEGIN_I_FORK
$display("person A Waiting for car, time=%0t", $time);
car_key.get(1);
$display("person A Got the car, time=%0t", $time);
#10;
car_key.put(1);
$display("person A Returning back car, time=%0t", $time);
end :BEGIN_I_FORK
begin :BEGIN_II_FORK
#1;
$display("person B Waiting for car, time=%0t", $time);
void'(car_key.try_get(1));
$display("person B Got the car, time=%0t", $time);
#10;
car_key.put(1);
$display("person B Returning back car, time=%0t", $time);
end :BEGIN_II_FORK
join
end :BEGIN_I
endmodule:semaphore_exa_get_try
Output:
On above code we create a 1 key. At time 0ns person A waiting for key and get a key from semaphore. At 1ns time person B waiting for key and 1ns there no key in semphore but here use try_get methos so it do not block the next statement so at 1ns it display person B Got the car.At the 10ns time in process-1 put the key and dispaly Person A returning back car.At 11ns time in process-2 put the key and display person B returning back car.
3-Mailbox#
A System-Verilog mailbox is a way of communication between different processes to exchange data. One process can put data into a mailbox that stores data internally and can be retrieved by another process. Mailbox behaves as first-in, first-out (FIFO).
Types in mailbox#
Mailbox is classified into two types.
Based on size, mailbox can take two forms :-
1.Bounded
2.Unbounded
Generic Mailbox#
The generic mailbox can be put or get data of any data type like int, bit, byte, string, etc. By default, the mailbox is a type-less or generic mailbox.
Syntax
mailbox <mailbox_name>;
I. Bounded#
If the size of the mailbox is defined then it is a bounded mailbox. When the mailbox is full, no further data can be put in the mailbox until an item or data is get from the mailbox.
Syntax:-
mailbox <mailbox_name> = new(size);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<3;i++)begin:BEGIN_MAIN
if(m.num()==2)begin:BEGIN_1
$display("mailbox is full");
end:BEGIN_1
else
begin:BEGIN_2
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_2
end:BEGIN_MAIN
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
begin:BEGIN_MAIN
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
end:BEGIN_MAIN
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox mb = new(2);
initial begin:BEGIN_MAIN
a1 = new(mb);
b1 = new(mb);
repeat(3)
begin:BEGIN_1
a1.tra_data();
$display("...............................................");
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that a Class A was created which transmits 3 data’s at a time. We are checking whether the mailbox is full or not by num method. As in module we bounded our mailbox to 2, it will transmit two data, but for third data it shows mailbox is full as there is no space in it. For receiver since we restricted it to receive only one data at a time, it will be receiving only one data.This process repeats for 3 times as we have given repeat(3) in module.
Know more about num():- https://github.com/muneeb-mbytes/SystemVerilog_Course/wiki/19.Interprocess-Communication#2-num
II. Unbounded#
If the size of the mailbox is not defined then it is a unbounded mailbox.
Syntax:-
mailbox <mailbox_name> = new();
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<3;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
begin:BEGIN_MAIN
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
end:BEGIN_MAIN
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new();
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
$display("...............................................");
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that a Class A was created which transmits 3 data’s at a time. Unlike bounded ,as it will have unlimitted size it can take all the three data at a time and transmit them and the receiver only receive one data and after it receives next set of fresh three data comes in(since used repeat(3)) as it is unbounded.
Parameterized Mailbox#
The parameterized mailbox can be put or get data of particular data type. The parameterized mailbox is useful when data type needs to be fixed. For differences in data type, a compilation error will occur.
Syntax:-
mailbox #(<type>) <mailbox_name>
Code snippet:-
class A;
int i;
string country;
string place;
mailbox #(string) m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
country = "India";
place = "Kashmir";
m.put(country);
m.put(place);
$display("Transmitter: Country = %0s , must visit place = %0s",country,place);
country = "South Africa";
place = "Cape Town";
m.put(country);
m.put(place);
$display("Transmitter: Country = %0s , must visit place = %0s",country,place);
country = "Spain";
place = "Barcelona";
m.put(country);
m.put(place);
$display("Transmitter: Country = %0s , must visit place = %0s",country,place);
endtask
endclass:A
class B;
string country;
string place;
mailbox #(string) m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
m.get(country);
m.get(place);
$display("Receiver: Country = %0s , must visit place = %0s",country,place);
m.get(country);
m.get(place);
$display("Receiver: Country = %0s , must visit place = %0s",country,place);
m.get(country);
m.get(place);
$display("Receiver: Country = %0s , must visit place = %0s",country,place);
endtask
endclass:B
module tb();
A a1;
B b1;
int i;
mailbox #(string) main = new(6);
initial begin:BEGIN_MAIN
a1= new(main);
b1 = new(main);
$display("");
$display("");
a1.tra_data();
$display(".......................................................................");
b1.rec_data();
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that we had fixed our mailbox to string data type. Took two strings country and place and bounded the mailbox to size 6. Since the mailbox is of string type we will pass string values India, kashmir, South Africa ,Cape Town, Spain and Barcelona only. If any other data type it will throw compilation error.
Methods in Mailbox#
S.no | Method Name | Description |
---|---|---|
1. | new(function) | Returns mailbox handle. An argument represents bounded mailbox size otherwise, it is an unbounded mailbox. |
2. | num(function) | Returns number of messages in the mailbox. |
3. | put(task) | Blocking method that stores data in the mailbox. |
4. | get(task) | Blocking method to retrieve data from the mailbox. |
5. | try_put(function) | The non-blocking method that stores data in the mailbox if it is not full and returns 1 else 0. |
6. | try_get(function) | The non-blocking method which returns data if a mailbox is non-empty else returns 0. |
7. | peek(task) | Copies data from the mailbox without removing it from a mailbox. |
8. | try_peek(function) | Tries to copy data from the mailbox without removing it from a mailbox. |
I. new#
Mailboxes are created by this method.
Syntax:-
mailbox <mailbox_name> = new(size); // creates a bounded mailbox
mailbox <mailbox_name> = new(); // creates an unbounded mailbox
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task check();
if(m == null)begin:BEGIN_1
$display("Mailbox is not created");
end:BEGIN_1
else
$display("Mailbox is created");
for(i=0;i<3;i++)begin:BEGIN_2
a++;
m.put(a);
$display("Value of a = %0d",a);
end:BEGIN_2
endtask
endclass:A
module tb();
A a1;
mailbox main = new(3);
initial begin:BEGIN_MAIN
a1= new(main);
$display("");
$display("");
a1.check();
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, we created a bounded mailbox of size 3 and we are checking it whether it has been created or not. Since it has been created we transmitted 3 data into it.
II. num#
This method returns the no of messages present in a mailbox.
Syntax:-
<mailbox_name>.num();
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<3;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] Transmitter: value of a = %0d",$time,a);
$display(" No of messages in mailbox = %0d",m.num());
end:BEGIN_MAIN
$display(".....................................................");
endtask
endclass:A
module tb();
A a1;
mailbox main = new();
initial begin:BEGIN_MAIN
a1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that we had created an unbounded mailbox and we are transmitting three data’s at a time. Since it is unbounded we don’t have any restrictions we can transmit all the data. Now for the first time of transmission, the passed values of a are 1, 2, 3 and the no of messages are three which can be seen by num() method. We repeated the process for two times so that we are able to pass 4, 5, 6 and now the no of messages in mailbox is 6.
III. put#
This method stores the data into the mailbox in FIFO order. It will block the process if mailbox is full.
Syntax:-
<mailbox_name>.put(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<4;i++)begin:BEGIN_MAIN
m.put(a);
#1 a++;
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display(".....................................................");
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
begin:BEGIN_1
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
end:BEGIN_1
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(3);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
$display("................................................................");
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 3 but we are trying to pass 4 data, since put is a blocking task it will not allow other task to perform until or unless it gets the fourth data, which is not possible(since size of mailbox is 3), so the program gets terminated.
IV. get#
This method can retrieve one message from the mailbox, if mailbox is empty it will block the process.
Syntax:-
<mailbox_name>.get(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<2;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display("put successful");
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
for(i =0;i<3;i++)begin:BEGIN_MAIN
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display("get successful");
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(2);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
$display("...............................................");
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 2 and we are trying to pass 2 data but at receiver side we are trying to receive 3 data at a time. So it will first receive 2 data as size is 2 and keeps on waiting for the other data. Since it is not possible it will terminate the program and will not print $display(“get successful”) line.
V. try_put#
This method tries to put the data in a non blocking manner to store a message in the mailbox if not full. If successful returns 1 else 0.
Syntax:-
<mailbox_name>.try_put(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<4;i++)begin:BEGIN_MAIN
a++;
if( m.try_put(a))
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
else
$display("failed while trying to put data=%0d",a);
end:BEGIN_MAIN
$display(".....................................................");
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
repeat(3) begin
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
end
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(3);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 3 but we are trying to pass 4 data, unlike put_method(which blocks the next set of execution),it will not block, but execute the next set of program. As you can see even though the mailbox is full it will go to next set of statements and prints $display(failed to get the value) statement.
VI. try_get#
This is a non-blocking method which tries to get one message from the mailbox, returns 0 if mailbox is empty.
Syntax:-
<mailbox_name>.try_get(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i =0;i<4;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display("put successful");
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
repeat(5)begin:BEGIN_MAIN
if( m.try_get(a))
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
else
$display("Failed while getting the value as mailbox is empty ");
end:BEGIN_MAIN
$display("get successful");
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(4);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
repeat(2)
begin:BEGIN_1
a1.tra_data();
$display("...............................................");
b1.rec_data();
end:BEGIN_1
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 4 but we are trying to pass 4 data, but at receiver side we are trying to get 5 data at a time. So at first we are transmitting a values 1,2,3,4 and at receiver side we are waiting for the fifth data as well. Since it is non blocking method, it will go to the next set of execution and prints (“get successful”).
VII. peek#
This method copies one message from the mailbox without removing the message from the mailbox queue.
Syntax:-
<mailbox_name>.peek(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i=0;i<1;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display("put successful");
$display("Messages in mailbox = %0d",m.num());
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
for(i =0;i<2;i++)begin:BEGIN_MAIN
m.peek(a);
$display("[%0t] Peeking value of a = %0d",$time,a);
$display("Peek successful");
end:BEGIN_MAIN
m.get(a);
$display("[%0t] 2. Receiver: value of a = %0d",$time,a);
$display("get successful");
$display("Messages in mailbox = %0d",m.num());
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(2);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
a1.tra_data();
$display("...............................................");
b1.rec_data();
$display("...............................................");
b1.rec_data();
$display("End of program");
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 2 but we are transmitting only 1 data, but at receiver we are peeking(copy) the transmitted value twice (a =1). Now the mailbox is empty, since Peek is a blocking task, when we tried calling bi.rec_data() again it will block all statements after m.peek(a) and so will not display End of program.
VIII. try_peek#
This method tries to copy data from mailbox without removing it from mailbox.
Syntax:-
<mailbox_name>.try_peek(arguments);
Code snippet:-
class A;
int a;
int i;
mailbox m;
function new(mailbox m1);
this.m = m1;
endfunction
task tra_data();
for(i=0;i<1;i++)begin:BEGIN_MAIN
a++;
m.put(a);
$display("[%0t] 1. Transmitter: value of a = %0d",$time,a);
end:BEGIN_MAIN
$display("put successful");
$display("Messages in mailbox = %0d",m.num());
endtask
endclass:A
class B;
int a;
int i;
mailbox m;
function new(mailbox m2);
this.m = m2;
endfunction
task rec_data();
for(i =0;i<2;i++)begin:BEGIN_MAIN
if( m.try_peek(a)) begin:BEGIN_1
$display("[%0t] Peeking value of a = %0d",$time,a);
$display("Peek successful");
end:BEGIN_1
else
begin
$display("Peek failed as mailbox is empty");
return;
end
end:BEGIN_MAIN
m.get(a);
$display("Receiver: value of a = %0d",a);
$display("get successful");
endtask
endclass:B
module tb();
A a1;
B b1;
mailbox main = new(2);
initial begin:BEGIN_MAIN
a1 = new(main);
b1 = new(main);
a1.tra_data();
$display("...............................................");
b1.rec_data();
$display("...............................................");
b1.rec_data();
$display("End of program");
end:BEGIN_MAIN
endmodule:tb
Output:-
In the above fig, you can see that mail box is of size 2 but we are transmitting only 1 data, but at receiver we are peeking(copy) the transmitted value twice (a =1). Now the mailbox is empty, since try_peek is a blocking task, when we tried calling bi.rec_data() again it will try peeking the value. As the mailbox is empty it will print peek is failed and now End of program will also get executed.