|
|
|
|
|
|
|
|
|
|
|
Variables Inside Methods
|
|
|
To declare a local variable inside a method is same as declaring in a struct, only difference is the variable declaration should start with reserve word var as shown in example below.
|
|
|
|
|
|
Variables declared inside a method can not be accessed by other methods or outside the method which declares. Thus we call them local variables.
|
|
|
|
|
|
1 <'
2 struct scoreboard {
3 // This is global variable
4 ! mem_list : list of int;
5 // Just another method
6 add_item (addr : int) is {
7 mem_list.push(addr);
8 // This is local variable
9 var i : int = 0; // We can assign a default value
10 };
11 };
12 '>
You could download file methods_ex18.e
here
|
|
|
|
|
|
Invoking Methods
|
|
|
Depending on if the method is time consuming method or regular method or we want to make the time consuming method to run as thread we can invoke method as one the way listed below.
|
|
|
|
|
|
- tcm()
- start tcm()
- method()
- compute method()
|
|
|
|
|
|
tcm()
|
|
|
A TCM can be called from another TCM. A called TCM begins execution either when its sampling event occurs or immediately, if the sampling event has already occurred for the current Specman tick.
|
|
|
|
|
|
The calling TCM waits until the called TCM returns before continuing execution. For this reason, a called TCM is considered a subthread of the calling TCM and shares the same thread handle (thread ID) with the calling TCM.
|
|
|
|
|
|
1 <'
2 struct memory_driver {
3 // Define a event for posedge of clock
4 event pos_clk is rise('top.clk')@sim;
5 // Define a method to drive memory write
6 mem_write( data: byte, addr : byte ) @pos_clk is {
7 // Wait for one cycle and drive command
8 wait [1]*cycle;
9 'top.mem_en' = 1;
10 'top.mem_addr' = addr;
11 'top.mem_data' = data;
12 'top.mem_wr' = 1;
13 outf("Writing to Address %x with Data %x\n",addr,data);
14 // Wait for one cycle and deassert the command
15 wait [1]*cycle;
16 'top.mem_en' = 0;
17 'top.mem_addr' = 0;
18 'top.mem_data' = 0;
19 'top.mem_wr' = 0;
20 };
21 // We use this TCM to call mem_write TCM
22 mem_tst()@pos_clk is {
23 mem_write(0x10, 0x5);
24 mem_write(0x15, 0x6);
25 mem_write(0xAA, 0x7);
26 out("Done with Simulation");
27 };
28 };
29 '>
You could download file methods_ex10.e
here
|
|
|
|
|
|
|
|
|
|
|
|
start tcm()
|
|
|
You can use a start action within another method, either a TCM or a regular method. A started TCM begins execution either when its sampling event occurs or immediately, if the sampling event has already occurred for the current Specman tick.
|
|
|
|
|
|
A started TCM runs in parallel with the TCM that started it on a separate thread. A started TCM has a unique thread handle (thread ID) that is assigned to it automatically by the scheduler. You can retrieve this handle using one of the predefined methods of the scheduler.
|
|
|
|
|
|
The recommended way to start an initial TCM, which can then invoke other TCMs, is to extend the related struct's predefined run() method.
|
|
|
|
|
|
- A TCM that has a return value cannot be started with a start action.
- You cannot start a TCM before the run phase begins or after the check phase begins
|
|
|
|
|
|
1 <'
2 // Note : We need a verilog code and Verilog simulator
3 // to simulate below example
4 struct memory_driver {
5 // Define a event for posedge of clock
6 event pos_clk is rise('top.clk')@sim;
7 // Define a method to drive memory write
8 mem_write( data: byte, addr : byte ) @pos_clk is {
9 // Wait for one cycle and drive command
10 wait [1]*cycle;
11 'top.mem_en' = 1;
12 'top.mem_addr' = addr;
13 'top.mem_data' = data;
14 'top.mem_wr' = 1;
15 outf("Writing to Address %x with Data %x\n",addr,data);
16 // Wait for one cycle and deassert the command
17 wait [1]*cycle;
18 'top.mem_en' = 0;
19 'top.mem_addr' = 0;
20 'top.mem_data' = 0;
21 'top.mem_wr' = 0;
22 };
23 // We use this TCM to call mem_write TCM
24 mem_tst()@pos_clk is {
25 mem_write(0x10, 0x5);
26 mem_write(0x15, 0x6);
27 mem_write(0xAA, 0x7);
28 out("Done with Simulation");
29 };
30 };
31
32 extend sys {
33 memory_driver : memory_driver;
34 run() is also {
35 // since the method is tcm use start
36 // Using start causes TCM run as parallel thread
37 start memory_driver.mem_tst();
38 };
39 };
40 '>
You could download file methods_ex11.e
here
|
|
|
|
|
|
method()
|
|
|
The proper context for calling a regular method depends on whether the method returns a value or not.
|
|
|
|
|
|
- If the method returns a value, it is an expression and can be called from any context where an expression is valid.
- If the method does not return a value, it is an action and can be called from any context where an action is valid.
|
|
|
|
|
|
1 <'
2 define HIGH 100;
3 define LOW 50;
4 struct memory_gen {
5 ! err_cnt : int;
6 ! war_cnt : int;
7 // Define a event for posedge of clock
8 event pos_clk is rise('top.clk')@sim;
9
10 // Define a method to check valid address
11 addr_valid(addr : byte ):bool is {
12 // Check if address is between HIGH and LOW value
13 // Wait for one cycle and drive command
14 if ((addr < LOW) || (addr > HIGH)) {
15 return FALSE;
16 } else {
17 return TRUE;
18 };
19 };
20
21 // This method prints the error and warning count
22 print_status() is {
23 outf("Number of Warnings : %d",war_cnt);
24 outf("Number of Errors : %d",err_cnt);
25 };
26
27 // We use this TCM to generate commands,drive them
28 // and call out methods
29 mem_txgen()@pos_clk is {
30 var addr : byte;
31 // Repeat (NO_COMMANDS)
32 // generate write/read commands
33 // Check address
34 if (addr_valid(addr)) {
35 // Drive to DUT
36 } else {
37 out ("address is not valid, skipping driver");
38 };
39 // End repeat
40 // Call the status method
41 print_status();
42 // Stop simulation
43 };
44 };
45 '>
You could download file methods_ex12.e
here
|
|
|
|
|
|
compute method()
|
|
|
In some cases you may want to call a value-returning method without using the value that is returned. To do this, you can use the compute action.
|
|
|
1 <'
2 define HIGH 100;
3 define LOW 50;
4 define ERR_LIMIT 200;
5 struct memory_gen {
6 ! err_cnt : int;
7 ! war_cnt : int;
8 // Define a event for posedge of clock
9 event pos_clk is rise('top.clk')@sim;
10
11 // Define a method to check valid address
12 addr_valid(addr : byte ):bool is {
13 // Check if address is between HIGH and LOW value
14 // Wait for one cycle and drive command
15 if ((addr < LOW) || (addr > HIGH)) {
16 return FALSE;
17 } else {
18 return TRUE;
19 };
20 };
21
22 // This method prints the error and warning count
23 print_status():bool is {
24 outf("Number of Warnings : %d",war_cnt);
25 outf("Number of Errors : %d",err_cnt);
26 if (err_cnt >= ERR_LIMIT) {
27 return FALSE;
28 } else {
29 return TRUE;
30 };
31 };
32
33 // We use this TCM to generate commands,drive them
34 // and call out methods
35 mem_txgen()@pos_clk is {
36 var addr : byte;
37 // Repeat (NO_COMMANDS)
38 // generate write/read commands
39 // Check address
40 if (addr_valid(addr)) {
41 // Drive to DUT
42 } else {
43 out ("address is not valid, skipping driver");
44 };
45 // End repeat
46 // Call the status method, Since it returns a value
47 // Which is no use to us, we use 'compute'
48 compute print_status();
49 // Stop simulation
50 };
51 };
52 '>
You could download file methods_ex13.e
here
|
|
|
|
|
|
return
|
|
|
Returns immediately from the current method to the method that called it. The execution of the calling method then continues.
|
|
|
|
|
|
It is not always necessary to provide a return action. When a value returning method ends without a return action, the value of result is returned. Any actions that follow a return action in the method definition are ignored. Actions placed in a method extension are performed before the return is executed.
|
|
|
|
|
|
1 <'
2 define HIGH 100;
3 define LOW 50;
4 define ERR_LIMIT 200;
5 struct memory_gen {
6 ! err_cnt : int;
7 ! war_cnt : int;
8 // Define a event for posedge of clock
9 event pos_clk is rise('top.clk')@sim;
10
11 // Define a method to check valid address
12 // This method shows how to use result
13 addr_valid(addr : byte ):bool is {
14 // Check if address is between HIGH and LOW value
15 // Wait for one cycle and drive command
16 if ((addr < LOW) || (addr > HIGH)) {
17 result = FALSE;
18 } else {
19 result = TRUE;
20 };
21 };
22
23 // This method prints the error and warning count
24 // This method shows how to use return
25 print_status():bool is {
26 outf("Number of Warnings : %d",war_cnt);
27 outf("Number of Errors : %d",err_cnt);
28 if (err_cnt >= ERR_LIMIT) {
29 return FALSE;
30 } else {
31 return TRUE;
32 };
33 };
34
35 // This method shows how to use return without a value
36 print_parity(data:byte, addr:byte) is {
37 if (addr_valid(addr)) {
38 var parity : bit = data[7:7]^data[6:6]^data[5:5]^
39 data[4:4]^data[3:3]^data[2:2]^
40 data[1:1]^data[0:0];
41 outf ("Parity of data is %b\n", parity);
42 } else {
43 return;
44 // This will not be executed
45 outf ("Address is not valid");
46 };
47 };
48
49 // We use this TCM to generate commands,drive them
50 // and call out methods
51 mem_txgen()@pos_clk is {
52 var addr : byte;
53 // Repeat (NO_COMMANDS)
54 // generate write/read commands
55 // Check address
56 if (addr_valid(addr)) {
57 // Drive to DUT
58 } else {
59 out ("address is not valid, skipping driver");
60 };
61 // End repeat
62 // Call the status method, Since it returns a value
63 // Which is no use to us, we use 'compute'
64 compute print_status();
65 // Stop simulation
66 };
67 };
68 '>
You could download file methods_ex14.e
here
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|