Featured post

Top 5 books to refer for a VHDL beginner

VHDL (VHSIC-HDL, Very High-Speed Integrated Circuit Hardware Description Language) is a hardware description language used in electronic des...

Sunday, 9 September 2012

Range Specification

Formal Definition

The range specification can be used to specify an array of gate or module instances.

Simplified Syntax

instance_name[l_index:r_index] (list of terminals);

Description

The range should be specified using two constant expressions separated by a colon and bracketed by square brackets. The expressions constitutes: the left-hand index (l_index) and right-hand index (r_index). The left-hand index can be less than, equal, or greater than the right-hand index (Example 1). If these indexes are equal then only one instance will be generated (Example 2). Identical instance names cannot appear twice with other range specifications (even if ranges do not overlap each other).

Examples

Example 1

reg [3:0] a, b;
wire [3:0] y;
and g[3:0](y,a,b);

This declaration is equivalent to:

and g3 (y[3], a[3], b[3]);
and g2 (y[2], a[2], b[2]);
and g1 (y[1], a[1], b[1]);
and g0 (y[0], a[0], b[0]);

Example 2

reg a, b;
wire y;
or g[0:0](y,a,b);

This declaration is equivalent to:
or g (y, a, b);

Important Notes

· If the range is used in module or gate instantiations, then terminals of all output ports should not be scalars or there may be a bus conflict.


Procedural Continuous Assignments

Formal Definition

Procedural continuous assignments provide a means to continuously drive a value into a register or a net.

Simplified Syntax

assign register_assignment ;
deassign register_left_value ;
force register_assignment | net_assignment ;
release register_left_value | net_left_value ;
register_left_value - left hand-side operand ;
net_left_value - left hand-side operand ;

Description

In the assign statement, the left hand-side operand can be a register or a concatenation of registers in contrast to continuous assignments where the left hand-side operands are nets. However, the memory word, bit-select or part-select cannot be used on the left hand-side. The priority of procedural continuous assignment is higher than that of the procedural assignments. The deassign keyword informs the end of the driving of the corresponding register. After a deassign, register values remain the same until driven by another procedural or procedural continuous assignment. If the assign keyword is used a second time for the same register, the first register will be deassigned and a new procedural continuous assignment statement takes place.

The keywords force and release have the same effect as assign and deassign; however the left hand-side operand should be a net or a bit-select or a part-select of vector net or concatenation of both. It cannot be part-select or bit-select of a vector register or a memory word.

An assign declared as a force overrides all procedural assignments to the register until the release statement is executed. In the same way, if a net is driven by a procedural continuous assignment all previous assignments are overridden until the release statement is executed. In the register case, the value will be maintained to the next procedural continuous assignment.

Examples

Example 1

module example1(clk, d, reset, set, q) ;
input clk, d, reset, set;
output q;
reg q;
  always @(posedge clk) q = d;
  always @(reset or set) begin
  if (reset) assign q = 1'b0;
  else if (set) assign q= 1'b1;
  else deassign q;
  end
endmodule

Important Notes

  • The left-hand operand of the force and release statements can be a net data type variable.
  • Assign and deassign can only be applied to reg type variables.

Procedural Timing Control

Formal Definition

The procedural timing control is used to determine when statements should be executed.

Simplified Syntax

Delay control:

  #delay

  #(min:typ:max delay)

Event type declaration:

  event identifier;

Event trigger:

  -> event_identifier;

Event control:

  @(event_identifier)

  @(posedge identifier)

  @(negedge identifier)

  @(event_expression or event_expression)

Wait statement:

  wait (expression) statement

Description

The Verilog HDL has two types of timing controls: delay control (Example 1) and event control (Example 2).

The delay control specifies the time between encountering and executing the statement. The delay control can be specified as a simple delay and as min:typ:max delay.

The named event (Example 3) is a special data type that does not hold any value. The event can be triggered using special characters -> followed by an event identifier. Any occurrence of an event trigger can be noticed using an event control statement.

An event control specifies the event that is required to resume execution of a statement. Event can be one of the following:

· Named event

· Change of a signal value

· Positive or negative edge occurred on signal (posedge, negedge)

· List of above-mentioned events (separated by or - event or operator)

A posedge is any transition from 0, x, and z to 1, and from 0 to z or x.

A negedge is any transition from 1, x, and z to 0, and from 1 to z or x.

The wait statement (Example 4) will suspend execution of all statements until the expression becomes true.

Examples

Example 1

#10;

The next statement will be executed after 10 time units.

#10 a = 5;

Assignment to a variable will be delayed by 10 time units.

#(1:2:3);

Delay control with min:typ:max delay value.

#(5:3:7) a = 5;

Assignment to a variable delayed by min:typ:max delay value.

Example 2

@ready a = a + 1;

The 'a' variable will be incremented by 1 when a change occurs on the 'ready' variable.

@(posedge clk) q = d;

The 'd' variable will be assigned to 'q' on the positive edge of clk.

@(a or b or c or d)
y = (a | b) & (~c ^ d);

A new value will be assigned to the 'y' variable when a change occurs on any of the variables a, b, c, or d.

Example 3

event e;

Event declaration.

initial begin
  #10;
  -> e;
end

Example of event triggering.

always @e d = 0;

Example of waiting for an event.

Example 4

wait (a);
i = i + 1;
wait (!a);

This sequence of statements will wait until 'a' becomes 1, and then the next statement will be executed. Next, execution will be suspended until 'a' becomes 0.

Important Notes

· The delay controls are useful in specifying patterns for testbenches.


Procedural Assignments

Formal Definition

The procedural assignments enable updating registers.

Simplified Syntax

register_identifier = expression;

register_identifier <= expression;

Description

The procedural assignments can be used only within the structured procedures (always, initial, task, function).

The left-hand side of assignment should be one of the following:

· Register.

· Bit-select of register.

· Part-select of reg, integer, or time data type.

· Memory word.

· Concatenation of any of the above.

The Verilog HDL contains two types of procedural assignments statements: blocking (Example 1) and non-blocking (Example 2) procedural assignments.

If a current statement contains a blocking procedural assignment then the next statement will be executed after the execution of the current statement (in the next step of the simulation).

If a current statement contains a non-blocking procedural assignment then the next statement will be executed at the same time (in the same step of the simulation).

A block of statements with non-blocking procedural assignments has similar functionality as a group of statements within a fork-join block (Example 3).

Examples

Example 1

begin
  a = 1;
  #10 a = 0;
  #5 a = 4;
end

During the simulation, this block will be executed in 15 time units. At time 0 the 'a' variable will be 1, at time 10 the 'a' variable will be 0, and at time 15 (#10 + #5) the 'a' variable will be 4.

Example 2

begin
  a <= 1;
  #10 a <= 0;
  #5 a <= 4;
end

During the simulation this block will be executed in 10 time units. At time 0 the 'a' variable will be 1, at time 5 the 'a' variable will be 4, and at time 10 the 'a' variable will be 0.

Example 3

fork
  a = 1;
  #10 a = 0;
  #5 a = 4;
join

This fork-join block has the same functionality as the block with non-blocking assignments from example 2.

Important Notes

· Statements that contain the non-blocking procedural assignments are executed in the same simulation cycle.


Probabilistic Distribution Functions

Formal Definition

Probabilistic Distribution Functions provide the functionality of random number generators.

Simplified Syntax

$dist_uniform (seed, start, end) ;

$dist_normal (seed, mean, standard_deviation) ;

$dist_exponential (seed, mean) ;

$dist_poisson (seed, mean) ;

$dist_chi_square (seed, degree_of_freedom) ;

$dist_t (seed, degree_of_freedom) ;

$dist_erlang (seed, k_stage, mean) ;

Description

Probabilistic distribution functions present a way to test your design using a randomly generated data. Testbenches often do not reveal irregularities in working models because designers tend to write testbenches in a schematic fashion. Usually, test vectors applied to the inputs of a module do not cover all possible states. When used, these functions may find a specific input combination for which the model does not work correctly. To enable repetitive design debugging, the probabilistic distribution functions must return recurrent data. This means that each time they are called they should return the same values in the last call order.

Probabilistic distribution functions use several arguments for generating data. A first function argument is a seed. Each time a function is called, the seed argument determines an order of values that are returned from the function. This argument must be a register type value of an inout direction. Users can initialize this value and let the system override it. This will make these functions repetitive.

The $dist_uniform function returns an integer value that is a random generated number in a range depending on the start and end arguments. Returned values are uniformly distributed. Both start and end arguments can be any integer, positive or negative, however the start value should be smaller than the end value.

The $dist_normal function returns a number that is an average approach to the mean argument. The mean argument is also used in $dist_expotential, $dist_poisson and$dist_erlang. The standard_deviation argument is used to determine the shape of density. In $dist_chi_square and $dist_t the shape of density depends on the degree_of_freedom.

Examples

Example 1

reg [15:0] a ;
initial begin
  a = $dist_exponential(60, 24);
end

Example 2

reg [15:0] a ;
initial begin
  a = $dist_erlang(60, 24, 7) ;
end

Important Notes

· To enable repetitive design debugging, the probabilistic distribution functions return recurrent data.


PLA Modeling Tasks

Formal Definition

The PLA system tasks are used to model PLA devices.

Simplified Syntax

$array_type$logic$format (memory_name, input_terms, output_terms) ;

array_type ::= sync | async

logic ::= and | or | nand | nor

format ::= array | plane

memory_name ::= identifier

input_terms ::= {scalar_variable}

output_terms ::= {scalar_variable}

Description

These system tasks are used to model content addressed memories i.e., memories that are read at locations that an input address matches a stored address. The PLA devices can be synchronous or asynchronous (type is defined by array_type: sync and async).

All patterns should be loaded into memory using the $readmemb and $readmemh system tasks or assigned by procedural assignments.

Both the input_terms and the output_terms should be concatenations of scalar variables, but all variables from the output_terms should be declared as a reg data type. Theinput_terms should have the length equal to the memory word size. The output_terms should have the length equal to the number of memory words (Example 1).

The input data is taken from the input_terms and then compared with all patterns from memory. If any pattern from the memory matches the input data then the corresponding bit of the output_terms becomes '1'.

The format specifies the logic type of an array. If an array is used, then only the bits with '1' value from the pattern are compared with the input data. If plane is used, then both '0' and '1' values are significant. The don't care values can also be specified by 'z' and '?' characters. (Example 3).

The logic identifier specifies how the input data should be compared with patterns (it also depends on the logic type of an array). If there is an and identifier then all bits with '1' value (array type) or all bits with '0' and '1' value (plane type) from the pattern should match the corresponding bits from the input data (Example 2). If a or identifier is used then at least one bit with '1' value (array type) or at least one bit with '0' or '1' value (plane type) from the pattern should match the corresponding bit from the input data.

The contents of a memory can be changed during the simulation.

Examples

Example 1

module pla(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2);
input a0, a1, a2, a3, a4, a5, a6, a7;
output b0, b1, b2;
reg b0, b1, b2;
reg [7:0] mem[0:2];
initial begin
  mem[0] = 8'b11001100;
  mem[1] = 8'b00110011;
  mem[2] = 8'b00001111;
  $async$and$array(mem, {a0,a1,a2,a3,a4,a5,a6,a7}, {b0,b1,b2});
  end
endmodule

The PLA device has an 8-bit input ([7:0]) bus and a 3-bit output ([0:2]) bus declared as reg (b0, b1, b2). This PLA device is an asynchronous array declared with logic and.

The simulation results for the PLA device from Example 1 are as follows:

A = {a0, a1, a2, a3, a4, a5, a6, a7}
B = {b0, b1, b2}
mem[0] = 8'b11001100;
mem[1] = 8'b00110011;
mem[2] = 8'b00001111;
A = 11001100 -> B = 100
A = 00110011 -> B = 010
A = 00001111 -> B = 001
A = 10101010 -> B = 000
A = 01010101 -> B = 000
A = 11000000 -> B = 000
A = 00111111 -> B = 011

All '1's from the pattern should match the '1's from the input data (the input data can also have other '1's)

The simulation results for the PLA device from Example 1 declared with $async$and$plane are as follows:

A = {a0, a1, a2, a3, a4, a5, a6, a7}
B = {b0, b1, b2}
mem[0] = 8'b11001100;
mem[1] = 8'b00110011;
mem[2] = 8'b00001111;
A = 11001100 -> B = 100
A = 00110011 -> B = 010
A = 00001111 -> B = 001
A = 10101010 -> B = 000
A = 01010101 -> B = 000
A = 11000000 -> B = 000
A = 00111111 -> B = 000

All '0's and '1's from the pattern should match the '0's and '1's from the input data.

If a PLA is declared with $async$and$plane then the pattern can be specified as 8'b0011????.

8'b0011???? -> ~a[0] & ~a[1] & a[2] & a[3]

The value of a[4], a[5], a[6], and a[7] bits are not important (the don't care values specified by '?' character).

Important Notes

  • If more than one pattern matches the input data then more than one output bit will go to '1'.


Part-select

Formal Definition

Part-select gives an access to contiguous bits of vectors.

Simplified Syntax

vector_identifier[msb:lsb];

Description

Part-select returns a part of a vector. The range is specified by two, separated by colon, constant expressions: the most significant bit (msb) in an expression and the least significant bit (lsb) in an expression. Both the msb expression and the lsb expression should be constant expressions.

The part-select operation can be applied to any net vector type, as well as reg, integers and time registers. The part-select of a register declared as real or realtime is illegal.

Part-select of a vector should be done in the same direction as the range of the declared vector.

Examples

Example 1

reg [3:0] vect;
vect = 4'b0001;

If the address expression is [3:1] then returned value is 000 (vect[3:1] = 3'b000).

If the address expression is [1:0] then returned value is 01 (vect[1:0] = 2'b01).

Important Notes

  • Part-select on memories, real registers, or realtime registers is illegal.