Serial & Parallel Blocks

Syntax (for parallel block):

fork

[parallel execution statements]

join

A Block is a section of Verilog code within a module which can be contained within begin...end statements. In many simulations different blocks run in parallel: operations from different blocks are executed in one time slice. Within a block it is more usual for commands to be executed in a serial manner, particularly when learning the language as this approack mirrors programing languages more closely. The following two examples illustrate serial execution:

         module serial_no_delay;
             reg       a, b;
             reg [1:0] x, y, z;

             initial begin                       EXAMPLE 1
                 a = 1'b0;
                 b = 1'b1;
                 x = {a, b};
                 y = {b, a};
                 z = y;
             end
         endmodule





         module serial_with_delays;
             reg       a, b;
             reg [1:0] x, y, z;

             initial begin                       EXAMPLE 2
                 a = 1'b0;
                 #20 b = 1'b1;
                 #10 x = {a, b};
                 #30 y = {b, a};
                 #30 z = y;
             end
         endmodule

In Example 1 all four operations are executed in time slice 0, but due to the operation of the complier, within the time slice they are executed serially: a is set to 0, then b to 1, then x to 01, then y to 10, then z to 10. If Example 1 were implemented in hardware a race condition would be set up - the way to aviod this would be to use non-blocking assignments. In Example 2 the operations are executed in the same order, but delays introduced so that they occur in different time slices: a is set to 0 in time slice 0, b to 1 in time slice 20, x to 01 in time slice 30, y to 10 in time slice 60, and z to 10 in time slice 90, after which the block will end.

It is, however, also possible to execute commands within blocks in parallel. The start of the section to be executed im parallel is marked by the fork command, and its end by the join command. The following example illustrates this:

         module parallel;
             reg       a, b;
             reg [1:0] x, y, z;

             initial begin                       EXAMPLE 3
                 fork
                     a = 1'b0;
                     #20 b = 1'b1;
                     #10 x = {a, b};
                     #30 y = {b, a};
                     #30 z = y;
                 join
             end
         endmodule

In Example 3 the operations within the fork...join commands all start at time slice 0. In time slice 0 a is set to 0. In time slice 10 x is set to {a, b} which, since b has not yet been assigned a value is 0x. In time slice 20 b is set to 1. In time slice 30 two operations are executed, y is set to 10, and z is set to y. This is a race condition since if y is set before z then z will be equal to 10, but if z is set first it will equal xx. This illustrates one of the hazards of parallel blocks and care must be taken to avoid race conditions - particularly since they will often not be highlighted by the simulator. The block will end after time slice 30.

Parallel blocks should be used whenever a block of code requires more than one operation to be carried out at a time. It can, for instance be used to create an a synchronos reset:

         module asynch_reset(reset);
             input   reset;
             integer i;

             initial begin                       EXAMPLE 4
                 fork :operation
                     forever
                         [main code];
                     @(posedge reset) disable operation;
                 join
             end
         endmodule

In Example 4 the main code is executed, but at the same time, i.e. in parallel, the reset line is being monitored for a positive edge on which to disable the operation block, and thus effect a reset.