2.0 Concurrency


The following Verilog HDL constructs are independent processes that are evaluated concurrently in simulation time:

Module Instance
Prinitive Instance
Contineous Assignment 
Procedural Blocks


Module Definations 



Port Order Connections

module_name instance_name [instance_array_range] (signal, signal, ... );

Port Name Connections

module_name instance_name [instance_array_range] (.port_name(signal), (.port_name(signal), ...);

Explicit Parameter Redefinition

defparam heirarchy_path.parameter_name = value;

Implicit Parameter Redefinition

module_name #(value) instance_name (signals);


A module may be instantiated using port order or port names.

  • Port order instantiation lists signal connections in the same order as the port list in the module definition. Unconnected ports are designated by two commas with no signal listed.
  • Port name instantiation lists the port name and signal connected to it, in any order.

instance_name (required) is used to make multiple instances of the same module unique from one another.

instance_array_range (optional) instantiates multiple modules, each instance connected to separate bits of a vector.

  • The range is specified as [lhi:rhi] (left-hand-index to right-hand-index).
  • If the bit width of a module port in the array is the same as the width of the signal connected to it, the full signal is connected to each instance of the module port.
  • If the bit width of a module port is different than the width of the signal connected to it, each module port instance is connected to a part select of the signal, with the right-most instance index connected to the right-most part of the vector, and progressing towards the left.
  • There must be the correct number of bits in each signal to connect to all instances (the signal size and port size must be multiples).

Parameters in a module may be redefined for each instance.

  • Explicit redefinition uses a defparam statement with the parameter's hierarchical name.
  • Implicit redefinition uses the # token as part of the module instantiation. Parameters must be redefined in the same order they are declared within the module.


Module Instance Examples

module reg4 (q, d, clock);
  output [3:0] q;
  input [3:0] d;
  input clock;
  wire [3:0] q, d;
  wire clock;
  //port order connection,2nd port not connected
  dff u1 (q[0], , d[0], clock);

  //port name connection, qb not connected
  dff u2 (.clk(clock),.q(q[1]),.data(d[1]));

  //explicit parameter redefine
  dff u3 (q[2], ,d[2], clock);
  defparam u3.delay = 3.2;

  //implicit parameter redefine
  dff #(2) u4 (q[3], , d[3], clock);
module dff (q, qb, data, clk);
  output q, qb;
  input data, clk;

  parameter delay = 1; //default delay parameter

  dff_udp #(delay) (q, data, clk);
  not (qb, q);


Array of Instances Example

module tribuf64bit (out, in, enable);
  output [63:0] out;
  input [63:0] in;
  input enable;
  wire [63:0] out, in;
  wire enable;
  //array of 8 8-bit tri-state buffers; each instance is connected
  //to 8-bit part selects of the 64-bit vectors; The scalar
  //enable line is connected to all instances

  tribuf8bit i[7:0] (out, in, enable);

module tribuf8bit (out, in, enable);
  output [7:0] y;
  input [7:0] a;
  input en;
  wire [7:0] y, a;
  wire en;
  //array of 8 Verilog tri-state primitives each bit of the
  //vectors is connected to a different primitive instance
  bufif1 u[7:0] (y, a, en);





Primitive Instance



gate_type (drive_strength) #(delay) instance_name [instance_array_range] (terminal, terminal, ... );
switch_type #(delay) instance_name [instance_array_range] (terminal, terminal, ... );


Gate Type

Terminal Order

(1_output, 1-or-more_inputs)
buf not (1-or-more_outputs, 1_input)
(1_output, 1_input, 1_control)
pullup pulldown (1_output)
user-defined-primitives (1_output, 1-or-more_inputs)


Switch Type

Terminal Order

(1_output, 1_input, 1_control)
cmos rcmos (1_output, 1_input, n_control, p_control)
tran rtran (2_bidirectional-inouts)
(2_bidirectional-inouts, 1_control)


Primitive Delay Syntax

#delay or #(delay)
   Single delay for all output transitions
#(delay, delay)
   Separate delays for (rising, falling) transitions
#(delay, delay, delay)
   Separate delays for (rising, falling, turn-off) transitions
   Minimum to maximum range of delays for all transitions
#(min_delay:typ_delay:max_delay, min_delay:typ_delay:max_delay)
   Min. to max. range of delays for (rising, falling) transitions
#(min_delay:typ_delay:max_delay, min_delay:typ_delay:max_delay, min_delay:typ_delay:max_delay)
   Min. to max. range of delays for (rising, falling, turn-off) transitions


delay (optional) represents the propagation delay through a primitive. The default delay is zero. Integers or real numbers may be used.

strength (optional) is specified as (strength1, strength0) or (strength0, strength1) Refer to Logic Strengths for strength keywords.

  • Only gate primitives may have drive strength specified. Switch primitives pass the input strength to the output. Resistive switches reduce the strength as it passes through.

instance_name (optional) may used to reference specific primitives in debugging tools, schematics, etc.

instance_array_range (optional) instantiates multiple primitives, each instance connected to separate bits of a vector.

  • The range is specified as [lhi:rhi] (left-hand-index to right-hand-index).
  • The primitive instances are connected with the right-most instance index connected to the right-most bit of each vector, and progressing towards the left.
  • Vector signals must be the same size as the array.
  • Scalar signals are connected to all instances in the array.


Primitive Instance Examples


and i1 (out,in1,in2); zero delay gate primitive
and #5 (o,i1,i2,i3,i4); same delay for all transitions
not #(2,3) u7(out,in); separate rise & fall delays
buf (pull0,strong1)(y,a); output drive strengths model ECL
wire [31:0] y, a;
buf #2.7 i[31:0] (y,a);
array of 32 buffers




Continueous Assignment




Explicit Continuous Assignment

net_type [size] net_name;
assign #(delay) net_name = expression;

Implicit Continuous Assignment

net_type (strength) [size] net_name = expression;

  • Explicit continuous assignments require two statements: one to declare the net, and one to continuously assign a value to it.
  • Implicit continuous assignments combine the net declaration and continuous assignment into one statement.
  • net_type may be any of the net data types except trireg.
  • strength (optional) may only be specified when the continuous assignment is combined with a net declaration. The default strength is (strong1, strong0).
  • delay (optional) follows the same syntax as primitive delays. The default is zero delay.
  • expression may include any data type, any operator, and calls to functions.
  • Continuous assignments model combinational logic. Each time a signal changes on the right-hand side, the right-hand side is re-evaluated, and the result is assigned to the net on the left-hand side.
  • Continuous assignments are declared outside of procedural blocks. They automatically become active at time zero, and are evaluated concurrently with procedural blocks, module instances, and primitive instances.


Continuous Assignment Examples

//A 32-bit wide 2:1 MUX
wire [31:0] mux_out;
assign mux_out = sel? a : b;
//A 16-bit wide tri-state buffer with delay
tri [0:15] #2.8 buf_out = en? in: 16'bz;
//A 64-bit ALU with ECL output strengths
wire [63:0] (strong1,pull0) alu_out = alu_function(opcode,a,b);




Procedural Blocks



type_of_block @(sensitivity_list)
  statement_group: group_name
  timing_control procedural_statements


type_of_block is either initial or always

  • initial procedural blocks process statements one time.
  • always procedural blocks process statements repeatedly.

sensitivity_list (optional) is an event timing control that controls when all statements in the procedural block will start to be evaluated. The sensitivity list is used to model combinational and sequential logic behavior.

statement_group--end_of_statement_group is used to group two or more procedural statements together and control the execution order.

  • begin--end groups two or more statements together sequentially, so that statements are evaluated in the order they are listed. Each timing control is relative to the previous statement.
  • fork--join groups two or more statements together in parallel, so that all statements are evaluated concurrently. Each timing control is absolute to when the group started.

group_name (optional) creates a local scope in a statement group. Named groups may have local variables, and may be disabled with the disable keyword.

local_variable_declarations (optional) must be a register data type (may only be declared in named statement groups).

timing_control is used to control when statements in a procedural block are executed. Refer to Procedural Timing

procedural_statement is a procedural assignment to a register variable or a programming statement

Procedural Block Examples


    bus = 16'h0000;
    #10 bus = 16'hC5A5;
    #20 bus = 16'hFFAA;
initial procedure executes statements one time; The fork--join group places statements in parallel.
always @(a or b or ci)
    sum = a + b + ci;
always procedure executes statements repeatedly.
always @(posedge clk)
  q <= data; 
a statement group is not required when there is only one statement