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...

Tuesday, 8 January 2013

Creating .lib file from Verilog netlist

Creating a dummy .lib file is something every physical design engineer has done now and then. If you have a verilog model of the block available, your task gets easier. The following script automates .lib generation from your verilog netlist. Use this as a dummy .lib to get your design flow going or use it as a template for your analog blocks for modifying the values.

Customize, edit and use. The script creates a simple Data Structure. So any modification can be done pretty easily. The script parses the verilog for the module name specified, and collects the ports & directions. In the .lib file written out, a default capacitance and transition value is specified. This is a good starting point for your blocks.

Usage: create_lib <verilog_netlist> <module_name> [transition_value] [capacitance_value]

#!/usr/bin/perl

use strict;

if ($#ARGV < 1 ) {
    print "usage: create_lib <verilog_netlist> <module_name> \n";
    exit;
}

my $netlist = $ARGV[0] ;
my $module  = $ARGV[1] ;
my $tran = 2.5 ;
my $cap = 0.001;
my $signal_level = "VDD" ;

if(defined $ARGV[2]) {$tran = $ARGV[2];}
if(defined $ARGV[3]) {$cap = $ARGV[3];}
if(defined $ARGV[4]) {$signal_level = $ARGV[4];}

my $FF;
my $FO;
open $FF, "< $ARGV[0]" or die "Can't open $ARGV[0] : $!";
open $FO, ">$module.lib" or die "Can't open $module.lib for write : $!";

my $db = createTopLevelDB();
createDotLib($db,$FO);

sub createDotLib
{
    my $topLevelDBRef = shift;
    my $FO = shift ;   
    ### Header
    print $FO "library\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
    print $FO "\n /* unit attributes */\n";
    print $FO "  time_unit : \"1ns\"\;\n";
    print $FO "  voltage_unit : \"1V\"\;\n";
    print $FO "  current_unit : \"1uA\"\;\n";
    print $FO "  pulling_resistance_unit : \"1kohm\"\;\n";
    print $FO "  leakage_power_unit : \"1nW\"\;\n";
    print $FO "  capacitive_load_unit\(1,pf\)\;\n\n";
    foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
        foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
            my @bus_width =  split(/_/, $bus_type);
            my $bus_hi = $bus_width[1] ;
            my $bus_lo = $bus_width[2] ;
            my $bus_width = $bus_hi+1-$bus_lo;
            print $FO " type \($bus_type\) { \n";
            print $FO "   base_type : array ; \n" ;
                print $FO "   data_type : bit  \n" ;;
                print $FO "   bit_width : $bus_width   \n" ;;
                print $FO "   bit_from : $bus_hi  \n" ;;
                print $FO "   bit_to : $bus_lo ; \n" ;
                print $FO "   downto : true ; \n" ;
                print $FO " } \n" ;
        }
    }
    print $FO "\n  cell\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
    foreach my $direction (keys(%{$topLevelDBRef->{'pins'}})) {
        foreach my $pin_name (@{$topLevelDBRef->{'pins'}->{$direction}}) {
            print $FO ("    pin\($pin_name\) { \n");
            print $FO ("\tdirection : $direction ;\n");
            if($direction eq "input") {
                print $FO ("\tmax_transition : $tran;\n");
            }
            print $FO ("\tcapacitance : $cap; \n");     
            print $FO ("    } \n") ;
        }
    }
    foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
        foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
            my @bus_width =  split(/_/, $bus_type);
            my $bus_hi = $bus_width[1] ;
            my $bus_lo = $bus_width[2] ;
            foreach my $bus_name (@{$topLevelDBRef->{'bus'}->{$direction}{$bus_type}}) {
                                        chomp($bus_name);
                print "BUS $bus_name : $bus_type : $direction \n" ;
                print $FO ("    bus\($bus_name\) { \n");
                print $FO ("\tbus_type : $bus_type ;\n");
                print $FO ("\tdirection : $direction ;\n");
                if($direction eq "input") {
                    print $FO ("\tmax_transition : $tran;\n");
                }   
                for(my $i=$bus_lo; $i<=$bus_hi; $i++) {
                    print $FO ("\tpin\($bus_name\[$i\]\) { \n");
                    print $FO ("\t\tcapacitance : $cap; \n"); 
                    print $FO ("\t} \n") ;
                }
                print $FO ("    } \n") ;
            }
        }
    }
    print $FO ("  } \n") ;
    print $FO ("} \n") ;
}

sub createTopLevelDB
{
    my $find_top_module = 0;
    my %topLevelDB = () ;
    my %pins = () ;
    my %bus = () ;
    my @input_pins ;
    my @output_pins ;
    my @inout_pins ;
    my @bus_types ;
    my %input_bus = () ;
    my %output_bus = () ;
    my %inout_bus = () ;
    my %design = ();
    $design{'cell'} = $module;
    $design{'tran'} = $tran;
    $design{'cap'} = $cap;
    $design{'signal_level'} = $signal_level;
    while(my $line = <$FF>) {
        last if($find_top_module == 1);
        if($line=~/module\s+$module/) {
            $find_top_module = 1 ;
            while(my $line = <$FF>) {
                next if($line =~ "\s*//" );
                chomp($line);
                if ($line =~/input\s+/ ) {
                    $line=~s/\s*input\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$input_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@input_pins, $pin);
                        }
                    }
                }
                if ($line =~/output\s+/ ) {
                    $line=~s/\s*output\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$output_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@output_pins, $pin);
                        }
                    }

                }
                if ($line =~/inout\s+/ ) {
                    $line=~s/\s*inout\s+//;
                    $line=~s/;//;
                    if($line =~/\[(\d+):(\d+)\]/) {
                        my $bus_type = "bus_$1_$2";
                        $line=~s/\[(\d+):(\d+)\]//;
                        my @line =  split(/,/, $line);
                        unless(grep {$_ eq $bus_type} @bus_types) { 
                            push(@bus_types,$bus_type);
                        }
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@{$inout_bus{$bus_type}}, $pin );
                        }
                    }
                    else {
                        my @line =  split(/,/, $line);
                        foreach my $pin (@line) {
                            $pin=~s/\s+//;
                            push(@inout_pins, $pin);
                        }
                    }

                }

                last if($line=~/endmodule/);
            }

        }
    }
    $pins{'input'} = \@input_pins;
    $pins{'output'} = \@output_pins;
    $pins{'inout'} = \@inout_pins;
    $bus{'input'} = \%input_bus;
    $bus{'output'} = \%output_bus;
    $bus{'inout'} = \%inout_bus;
    $topLevelDB{'pins'} = \%pins;
    $topLevelDB{'bus'} = \%bus;
    $topLevelDB{'design'} = \%design;
    return \%topLevelDB;
}

Monday, 7 January 2013

What to expect at the VLSI Conf Pune 2013

The 26th International Conference on VLSI Design is currently going on at the Hyatt, in Pune (Jan 7th to 9th, 2013), and with a large number of keynotes, research paper presentations, panel discussions, workshops and other things being presented in 5 different tracks to 800+ delegates, it is full of activity for anyone interested in the field of VLSI design/EDA/Embedded systems.

Here are the details of the technical program:

  • New Research Ideas
    • Often 5-10 years from practical applications
    • 3 parallel tracks from 7th to 9th Jan
  • User/Designer Track
    • Novel ideas to and from practitioners (not researchers)
    • Can be used today to enhance your next design
    • One track on 7th and 8th Jan
  • Student-Oriented Talks/Workshops
  • Design Contest
  • Industry Form
  • 9 keynotes: by people from LSI, IBM, Marvell, APM, Howard Hughes Medical Institute, Intel, Solarsis, Xilinx
  • Panels and Embedded Tutorials for people new to the field
  • 66 accepted talks, out of 310 submissions, in all areas of design/EDA/embedded systems

There are 23 companies who have set up exhibit stalls, and includes Intel, QLogic, Xilinx, TI, ARM, Agilent and a bunch of other companies, and includes many companies who have significant Pune presence.

 VLSI AND EMBEDDED SYSTEMS CONFERENCE PROGRAM

Day 1 7th January 2013 Inauguration, Technical Sessions, Exhibits, Student Conference
Day 2 8th January 2013 Valedictory/Award, Technical Sessions, Exhibits, Student Conference
Day 3 9th January 2013 Technical Sessions, Exhibits, RASDAT 2013
Day 4 10th January 2013 RASDAT 2013
Day T1 5th January 2013 Tutorials
Day T2 6th January 2013 Tutorials

VLSI AND EMBEDDED SYSTEMS CONFERENCE IMPORTANT DATES

Regular Paper Submissions

24th July, 2012 (Closed)

Tutorial Submissions

17th August, 2012 (Closed)

User/Designer Submissions

24th August, 2012 (Closed)

Call for embedded tutorials,

24th August, 2012 (Closed)

special sessions, and panels

Design Contest Submission

30th November, 2012 (Final deadline)

User Track Acceptance Notification

19th October, 2012 (Closed)

Camera ready paper due

15th October, 2012 (Closed)

Get free daily email updates!

Follow us!

Monday, 31 December 2012

Happy New Year 2013

We would also like to thanks all our esteemed readers and subscriber as yet again VLSI Encyclopedia has had its most successful year in terms of visitors, articles read, subscriber, Facebook and twitter fans in its history. Happy New Year !!!

2013-happy-new-year-wallpapers-171

Get free daily email updates!

Follow us!

SystemVerilog Interface

Interfaces are a major new construct in SystemVerilog, created specifically to encapsulate the communication between blocks, allowing a smooth refinement from abstract system-level through successive steps down to lower RTL and structural levels of the design. Interfaces also facilitate design re-use. Interfaces are hierarchical structures that can contain other interfaces.

There are several advantages when using an Interface:

  • They encapsulate connectivity: an interface can be passed as a single item through a port, thus replacing a group of names by a single one. This reduces the amount of code needed to model port connections and improves its maintainability as well as readability.
  • They encapsulate functionality, isolated from the modules that are connected via the interface. So, the level of abstraction and the granularity of the communication protocol can be refined totally independent of the modules.
  • They can contain parameters, constants, variables, functions and tasks, processes and continuous assignments, useful for both system-level modelling and testbench applications.
  • They can help build applications such as functional coverage recording and reporting, protocol checking and assertions.
  • They can be used for port-less access: An interface can be instantiated directly as a static data object within a module. So, the methods used to access internal state information about the interface may be called from different points in the design to share information.
  • Flexibility: An interface may be parameterised in the same way as a module. Also, a module header can be created with an unspecified interface instantiation, called a Generic Interface. This interface can be specified later on, when the module is instantiated.

At its simplest, an interface is a named bundle of wires, similar to a struct, except that an interface is allowed as a module port, while a struct is not.

// Interface definition
interface Bus;
  logic [7:0] Addr, Data;
  logic RWn;
endinterface


// Using the interface
module TestRAM;
  Bus TheBus();                   // Instance the interface
  logic[7:0] mem[0:7];
  RAM TheRAM (.MemBus(TheBus));   // Connect it

  initial
  begin
    TheBus.RWn = 0;               // Drive and monitor the bus
    TheBus.Addr = 0;
    for (int I=0; I<7; I++)
      TheBus.Addr = TheBus.Addr + 1;
    TheBus.RWn = 1;
    TheBus.Data  = mem[0];
  end
endmodule


module RAM (Bus MemBus);
  logic [7:0] mem[0:255];

  always @*
    if (MemBus.RWn)
      MemBus.Data = mem[MemBus.Addr];
    else
      mem[MemBus.Addr] = MemBus.Data;
endmodule


Interface Ports

An interface can also have input, output or inout ports. Only the variables or nets declared in the port list of an interface can be connected externally by name or position when the interface is instantiated, and therefore can be shared with other interfaces.  The ports are declared using the ANSI-style.

Here is an example showing an interface with a clock port:

interface ClockedBus (input Clk);
  logic[7:0] Addr, Data;
  logic RWn;
endinterface
module RAM (ClockedBus Bus);
  always @(posedge Bus.Clk)
    if (Bus.RWn)
      Bus.Data = mem[Bus.Addr];
    else
      mem[Bus.Addr] = Bus.Data;
endmodule


// Using the interface
module Top;
  reg Clock;

  // Instance the interface with an input, using named connection
  ClockedBus TheBus (.Clk(Clock));
  RAM TheRAM (.Bus(TheBus));
  ...
endmodule

Parameterised Interface

This is a simple example showing a parameterised interface:

interface Channel #(parameter N = 0)
    (input bit Clock, bit Ack, bit Sig);
  bit Buff[N-1:0];
  initial
    for (int i = 0; i < N; i++)
      Buff[i] = 0;
  always @ (posedge Clock)       
   if(Ack = 1)
     Sig = Buff[N-1];
   else
     Sig = 0;
endinterface

Tasks in Interfaces

Tasks and functions can be defined in interfaces, to allow a more abstract level of modelling.

The next example shows two tasks in an interface being used to model bus functionality. The tasks are called inside the testRAM module:

interface MSBus (input Clk);
  logic [7:0] Addr, Data;
  logic RWn;

  task MasterWrite (input logic [7:0] waddr,
                    input logic [7:0] wdata);
    Addr = waddr;
    Data = wdata;
    RWn = 0;
    #10ns RWn = 1;
    Data = 'z;
  endtask
  task MasterRead (input  logic [7:0] raddr,
                   output logic [7:0] rdata);
    Addr = raddr;
    RWn = 1;
    #10ns rdata = Data;
  endtask
endinterface
module TestRAM;
  logic Clk;
  logic [7:0] data;
  MSBus TheBus(.Clk(Clk));
  RAM TheRAM (.MemBus(TheBus));
  initial
  begin
    // Write to the RAM
    for (int i = 0; i<256; i++)
      TheBus.MasterWrite(i[7:0],i[7:0]);

    // Read from the RAM
    for (int i = 0; i<256; i++)
    begin
      TheBus.MasterRead(i[7:0],data);
      ReadCheck : assert (data === i[7:0])
        else $error("memory read error");
    end
  end
endmodule

Access Type

Formal Definition

A type that provides access to an object of a given type. Access to such an object is achieved by an access value returned by an allocator; the access value is said to designate the object.

Simplified Syntax

access subtype_indication
type identifier;

Description

Access type allows to manipulate data, which are created dynamically during simulation and which exact size is not known in advance. Any reference to them is performed via allocators, which work in a similar way as pointers in programming languages.
The subtype_indication in the access type declaration denotes the type of an object designated by a value of an access type. It can be any scalar, composite or other access type (example 1). File type is not allowed here.
The only objects allowed to be of the access type are variables.
The default value of an access type is null which designates no object at all. To assign any other value to an object of an access type an allocator has to be used (see allocator for details).
The access type allows to create recursive data structures (dynamic lists of objects created during simulation) which consist of the records that contain elements of access types - either the same or different than the actually declared. In order to handle declarations of such recursive data structures so called incomplete type declaration is needed which plays a role of an "announcement" of a type which will be declared later on.
For each incomplete type declaration there must be a corresponding full type declaration with the same name. The complete declaration must appear in the same declarative part. A type declared as incomplete may not be used for any other purposes than to define an access type before the complete type definition is accomplished. Such an incomplete type declaration is presented in example 2 below.

Examples

Example 1
-- declaration of record type Person:
type Person is record
            address:ADRESS_TYPE;
            age:DATE;
end record Person;
-- declaration of access type Person_Access:
type Person_Access is access Person;
The Person_Access type defines a pointer (dynamic link) to a record declared earlier and called Person.
Example 2
-- declaration of an incomplete type Queue_Element:
type Queue_Element;
-- declaration of an access type Queue_Element_Ptr:
type Queue_Element_Ptr is access Queue_Element;
-- declaration of an full record type Queue_Element:
type Queue_Element is record
                  name:STRING(1 to 20);
                  address:ADRESS_TYPE;
                  age:DATE;
                  succ:Queue_Element_Ptr;
end record Queue_Element;
The type Queue_Element contains the Queue_Element_Ptr field, which in turns points to Queue_Element. In order to declare both types sequentially, first the Queue_Element is declared in an incomplete way, which allows declaring the access type Queue_Element_Ptr. Finally, complete declaration of Queue_Element must be provided.

Important Notes

· Application of access types is restricted to variables: only variables can be of an access value. Also, only variables can be designated by an access value.
· Although access types are very useful for modeling potentially large structures, like memories or FIFOs, they are not supported by synthesis tools.













Aggregate

Formal Definition

A basic operation that combines one or more values into a composite value of a record or array type.

Syntax:

aggregate ::= ( element_association { , element association } ) element_association ::= [choices => ] expression choices ::= choice { | choice } choice ::= simple expression          | discrete_range          | element_simple_name          | others

Description

The aggregate assigns one or more values to the elements of a record or array creating the composite value of this type. Aggregates are composed of element associations, which associate expressions to elements (one expression per one or more elements). Element associations are specified in parentheses and are separated by commas.

An expression assigned to an element or elements must be of the same type as the element(s).

Elements can be referred to either by textual order they have in the object declaration (so called positional associations - example 1) or by its name (named associations - example 2). Both methods can be used in the same aggregate, but in such a case all positional associations appear first (in textual order) and all named associations appearing next (in any order). In any case if the association others is used, it must be the last one in an aggregate.

The choice clause, denoting selection of element(s) can have any of the following forms: simple expression, discrete range, simple name or reserved word others.

A value of simple expression can be applied in arrays only and must belong to discrete range of an array type. A simple expression specifies the element at the corresponding index value. Example 2 illustrates this concept.

A discrete range must meet the same conditions as a simple expression. It is useful when several consecutive elements of an array are assigned the same value (example 3). A discrete range serves for defining the set of indexes only and the direction specified or implied has no significance.

The use of element simple name as a choice is restricted to records only. In this case, each element is identified by its name (Example 4).

When some elements are assigned different values and the remaining elements will receive some other value, reserved word others can be used to denote those elements (Example 5). Such a choice must be the last in an aggregate and can be used both in arrays and in records, provided that the remaining elements of the records are of the same type.

The choice others can serve as a very convenient way to assign the same value to all elements of some array, e.g. to reset a wide bus (Example 6).

If several elements are assigned the same value, a multiple choice can be used. In such a case a bar sign (|) separates references to elements (Example 7). If a multiple choice is used in an array aggregate, it may not be mixed with positional associations.

Examples

Example 1

variable Data_1 : BIT_VECTOR (0 to 3) := ('0','1','0','1');

Bits number 0 and 2 are assigned the value '0', while bits 1 and 3 are assigned '1'. All element associations here are positional.

Example 2

variable Data_2 : BIT_VECTOR (0 to 3) := (1=>'1',0=>'0',3=>'1',2=>'0');

Like in the previous example, bits number 0 and 2 are assigned the value '0', while bits 1 and 3 are assigned '1'. The element associations here, however, are named. Note that in this case the elements can be listed in arbitrary order.

Example 3

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (15 downto 8 => '0', 7 downto 0 => '1');

Data_Bus will be assigned the value of "0000000011111111". The first element is associated a value in positional way (thus it is bit number 15), and the other two groups are assigned values using discrete ranges.

Example 4

type Status_Record is record
     Code : Integer;
     Name : String (1 to 4);
end record;
variable Status_Var : Status_Record := (Code => 57, Name => "MOVE");

Choice as an element simple name can be used in record aggregates - each element is associated a value (of the same type as the element itself).

Example 5

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (14 downto 8 => '0', others => '1');

Data_Bus will be assigned the same value as in example 3 ("1000000011111111"), but this aggregate is written in more compact way. Apart from bits 14 through 8, which receive value '0' all the others (15 and 7 through 0) will be assigned '1'. Note that the choice others is the last in the aggregate.

Example 6

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (others => 'Z');

Instead of assigning "ZZZZZZZZZZZZZZZZ" to Data_Bus in order to put it in high impedance state, an aggregate with the others choice representing all the elements can be used.

Example 7

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (15 | 7 downto 0 => '1',
others => '0');

Note the multiple choice specification of the assignment to the bits 15 and 7 through 0. The result of the assignment to Data_Bus will be the same as in examples 3 and 5 ("1000000011111111").

Important Notes

· Associations with elements' simple names are allowed in record aggregates only.

· Associations with simple expressions or discrete ranges as choices are allowed only in array aggregates.

· Each element of the value defined by an aggregate must be represented once and only once in the aggregate.

· Aggregates containing the single element association must always be specified using named association in order to distinguish them from parenthesized expressions.

· The others choice can be only the last in an aggregate.

Alias

Formal Definition

An alternate name for an existing named entity.

Simplified Syntax

alias alias_name : alias_type is object_name;

Description

The alias declares an alternative name for any existing object: signal, variable, constant or file. It can also be used for "non-objects": virtually everything, which was previously declared, except for labels, loop parameters, and generate parameters.

Alias does not define a new object. It is just a specific name assigned to some existing object.

Aliases are prevalently used to assign specific names to slices of vectors in order to improve readability of the specification (see example 1). When an alias denotes a slice of an object and no subtype indication is given then the subtype of the object is viewed as if it was of the subtype specified by the slice.

If the alias refers to some other object than a slice and no subtype indication is supported then the object is viewed in the same way as it was declared.

When a subtype indication is supported then the object is viewed as if it were of the subtype specified. In case of arrays, the subtype indication can be of opposite direction than the original object (example 2).

Subtype indication is allowed only for object alias declarations.

A reference to an alias is implicitly a reference to the object denoted by the alias (example 3).

If an alias denotes a subprogram (including an operator) or enumeration literal then a signature (matching the parameter and result type) is required (example 4). See signature for details.

Examples

Example 1

signal Instruction : Bit_Vector(15 downto 0);
alias OpCode : Bit_Vector(3 downto 0) is Instruction(15 downto 12);
alias Source : Bit_Vector(1 downto 0) is Instruction(11 downto 10);
alias Destin : Bit_Vector(1 downto 0) is Instruction(9 downto 8);
alias ImmDat : Bit_Vector(7 downto 0) is Instruction(7 downto 0);

The four aliases in the example above denote four elements of an instruction: operation code, source code, destination code and immediate data supported for some operations. Note that in all declarations the number of bits in the subtype indication and the subtype of the original object match.

Example 2

signal DataBus : Bit_Vector(31 downto 0);
alias FirstNibble : Bit_Vector(0 to 3) is DataBus(31 downto 28);

DataBus and FirstNibble have opposite directions. A reference to FirstNibble(0 to 1) is equivalent to a reference to DataBus(31 downto 30).

Example 3

signal Instruction : Bit_Vector(15 downto 0);
alias OpCode : Bit_Vector(3 downto 0) is Instruction(15 downto 12);
. . .
if Opcode = "0101" -- equivalent to if Instruction(15 downto 12) = "0101"
then
    . . .

Both conditions are exactly the same, but the one where alias is used is more readable.

Important Notes

· VHDL Language Reference Manual uses the name 'entity' to denote a language unit, i.e. object, parameter etc. It is completely different idea than a design entity.

· Many synthesis tools do not support aliases.