///  LSU EE 4755 -- Fall 2016 -- Digital Design / HDL
///
///  Objects and Data Types

 // Time-stamp: <16 September 2016, 13:12:11 CDT, koppel@dmk-laptop>

 // Under construction.

/// Contents

//  Identifiers
//  Objects - Nets and Variables
//  Integer Data Types
//  Some Operators
//  Floating Point Data Types
//  Net Object Types
//  Vectors and other Packed Arrays, Unpacked Arrays
//  Address Ranges in Declarations
//  Vectored and Scalared Declaration Modifiers
//  .. Other material under construction

/// References

// :SV12: IEEE 1800-2012 -- The SystemVerilog Standard
//        http://standards.ieee.org/getieee/1800/download/1800-2012.pdf
//
// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//        The text used in LSU EE 4720, 4730, and 4740.


////////////////////////////////////////////////////////////////////////////////
/// Lexical Conventions

//  :SV12: Chapter 5

/// :Def: Lexical Conventions
//        Boring details about what characters you can use for
//        things such as identifiers and whitespace.

 /// Highlights of SystemVerilog lexical conventions:
//
//   Identifiers (variable names, module names, etc.) are case sensitive.
//     For example, My_Module and my_module are different.
//     This is like C/C++, but unlike Fortran and VHDL.
//
//   Whitespace is a non-zero string of spaces, tabs, newlines, formfeeds.
//     Whitespace rules are similar to C.


//  Identifiers are used for module names, module instance names, and
//  variable names.

//  Identifiers:

//   First character must be alphabetic or an underscore (_);
//   Following characters may be alphabetic, digit, underscore, or dollar sign.
//   Case is significant. (myvar and Myvar are different identifiers)
//   Maximum length 1024.  That's a limit, not a goal.

// :Example:
//
//  Identifier Examples (in wire declarations).
//
module i_am_an_identifier();
   uwire this_is_an_identifier;
   uwire a, A;  // Two different variables.
   uwire a1;
   uwire icantreadthis;
   uwire his$is$hard$to$read$too;
   uwire but_this_I_can_read;
   uwire _this_works_too;
   uwire this_is_valid_identifier_but_unless_you_were_skilled_with_a_text_editor_it_would_be_really_difficult_to_use_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;

   uwire connection1, connection2, And, us, too;
   ModuleName ModuleInstanceName(connection1,connection2);
   I_m_also_an_idenfifier me_too(And,us,too);

endmodule

module ModuleName(output connection1,input connection2); endmodule
module I_m_also_an_idenfifier(output a, input b, c); endmodule


////////////////////////////////////////////////////////////////////////////////
/// Objects

// :SV12: Section 6.5 -- Not for beginners.
// :BV3: A.6.1 --  Good description, but pre-SystemVerilog

 /// Two Kinds of Objects :  Nets and Variables

 /// Nets
 //
 //  Are used to model connections between devices.
 //  Usually get values by being connected to something ...
 //  ... they are not normally assigned to.
 //  The are the default kind for module ports.

 /// Variables
 //
 //  These are like variables in most programming languages.
 //  Usually get a value by being assigned in procedural code.

 /// It Is Important to Understand Net/Variable Differences
 //
 //  In most cases an object needs to be either a net or a variable.
 //
 //  To avoid frustration and wasted time ...
 //  ... make sure that you understand the differences.

 /// Metaphorical Difference
 //
 //  A net is like a hose:
 //    It needs to be *connected to* something (a driver) ..
 //    ... that's always feeding it.
 //
 //  A var is like a cup:
 //    It can be filled, and refilled any number of times.
 //    Filling happens at particular points in time, not constantly.

// :Example:
//
// Quick example of declaring and using nets and variables.

module nt_examples(input [7:0] a);

   var int my_var;
   wire logic my_net, my_other_net;
   var  logic my_other_var;

   logic my_other_var_2;  // A var object. (Notice var omitted.)
   wire  my_other_net_2;  // A net of type logic. (Notice logic omitted.)

   assign my_net = a[0];
   some_mod inst_name(my_other_net,a);

   initial begin

      my_var = 3;
      my_other_var = a[1];
      #1;
      my_var = 4;

   end

   // Longer Declarations.
   //
   uwire logic [7:0] my_wire;  // Declaration of a net of type logic.
   var logic [7:0] my_var;     // Declaration of a variable of type logic.
   reg [7:0] my_var_v95;       // Verilog 1995 equivalent of my_var;
   uwire integer my_w_int;     // Declaration of a net of type integer;
   var integer my_v_int;       // Declaration of a variable of type integer;

   // Taking advantage of defaults.
   //
   uwire [7:0] my_wire2;  // Default data type is logic.
   logic [7:0] my_var2;   // Default object is variable.
   uwire integer my_w_int2;
   integer my_v_int2;


   // Quick Examples of Use
   //
   always_comb
     begin
        my_var = a;       // Okay, can assign to variables.
        // my_wire = 13;  // Error because can't assign wires.
     end

   some_module sm( my_wire, my_var ); // Okay to use wire here.

endmodule

module some_module(output [7:0] a, input [7:0] b); endmodule


 /// Nets v. Variables

 //  There are many rules about where each can be used.
 //
 //  But these are easy to remember if you keep in mind that:
 //
 //   Nets don't "remember" values, they must be connected to something.
 //
 //   Variables must be assigned in procedural code, not by a module output.



////////////////////////////////////////////////////////////////////////////////
/// Integer Data Types
///

 // :SV12: Section 6.11
 // :SV12: Section 6.3.1 Logic Values

 /// Two-State Integer Types
 //
 //  Like integers in ordinary programming languages.
 //  Bit values: 0 or 1.

 // :Keyword: bit      -  1 bit unsigned, 2-state.
 // :Keyword: byte     -  8 bit signed, 2-state.
 // :Keyword: shortint - 16 bit signed, 2-state.
 // :Keyword: int      - 32 bit signed, 2-state.
 // :Keyword: longint  - 64 bit signed, 2-state.

 // Use these in testbenches and other places not corresponding
 // directly to hardware, and for intermediate values in arithmetic
 // expressions.
 //
 /// In most cases use int.
 //
 // Use bit, byte, and shortint in large arrays ...
 // ... to save simulator memory.


 /// Four-State Integer Types
 //
 //  Used for simulation of hardware.
 //  Bit values: 0, 1, x, z.

 // :Keyword: logic    - user-defined size, unsigned, 4-state
 // :Keyword: integer  - 32-bit, signed, 4-state
 // :Keyword: time     - 64-bit, unsigned, 4-state

 // Use type logic to represent hardware, except for intermediate
 // values in arithmetic expressions.
 //
 // Type reg (not shown) is sort of a synonym for logic, and was used
 // in older versions of Verilog. Its name (reg) is misleading, which
 // is why logic is preferred.
 //
 // The integer and time types are also kept for compatibility with
 // old Verilog.


 /// Signed and Unsigned Qualifiers.
 //
 //  Can be used to modify 2- and 4-state integer types.

 // :Keyword: signed
 // :Keyword: unsigned

 //  Note: UNLIKE C, qualifier goes after type. (logic signed).
 //
 //  Note: Whether a type is signed or unsigned ...
 //  ... affects choice of operators ...
 //  ... but does not effect how data is stored.


// :Example:
//
// Use of types in a module that computes the maximum of two signed
// numbers.

module max_mod
  ( output logic signed [7:0] max,
    input  logic signed [7:0] a, b );

   // Type "logic" is used because we are modeling hardware.
   //
   // Qualifier "signed" is used because we want the simulator
   // and synthesis program to use the correct >= (greater than or
   // equal to) operator.
   //

   always_comb max = a >= b ? a : b;

endmodule

// Testbench for max module.
//
module max_demo_good();

   /// Max Module Inputs
   //
   // Type "logic" is used for a and m because that is the type of
   // max module's ports.
   //
   // Variable kind (as opposed to net) because assigned in procedural code.
   //
   logic signed [7:0] a;
   byte signed b; // Type "byte" works here, but should be avoided.

   /// Max Module Output
   //
   // "Net" kind (uwire) because connected to a module output.
   //
   // It is important to use a 4-state type, such as logic, so
   // that "x" and "z" types are visible.
   //
   uwire logic signed [7:0] m;

   max my_max(m,a,b);

   // Type "int" is used because there will be no hardware corresponding
   // to this variable (num_tests).
   localparam int num_tests = 20;

   initial begin

      for ( int i=0; i<num_tests; i++ ) begin

         // Type "int" used because this does not correspond to hardware.
         //
         int shadow_max;

         a = $random;  // Returns a 32-bit signed int type, cast to logic.
         b = $random;

         shadow_max = a >= b ? a : b;

         #10;

         if ( shadow_max !== m )
           $write("Wrong result  max(%d,%d)  %d != %d (correct)\n",
                  a, b, m, shadow_max);
      end

      $display("Done with %d tests.\n",num_tests);

   end

endmodule


// :Example:
//
// Another testbench for the max module, but this has errors due to
// forgetting about the signed qualifier.

module max_demo_bad();

   // Connections to my_max module declared without the "signed"
   // qualifier. Values will be unsigned.
   //
   logic [7:0] a, b;
   uwire logic [7:0] m;

   max my_max(m,a,b);

   // Type "int" is used because there will be no hardware corresponding
   // to this variable (num_tests).
   localparam int num_tests = 20;

   initial begin

      for ( int i=0; i<num_tests; i++ ) begin

         // Type "int" used because this does not correspond to hardware.
         //
         int shadow_max;

         a = $random;
         b = $random;

         shadow_max = a >= b ? a : b;

         #10;

         if ( shadow_max !== m )
           $display("Wrong result  max(%d,%d)  %d != %d (correct)\n",
                  a, b, m, shadow_max);
      end

      $display("Done with %d tests.\n",num_tests);

   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Some Operators

// :SV12: Section 11 -- Operators and Expressions Chapter
// :SV12: Table 11-1 -- Table showing many operators.

 /// System Verilog Operators
//
//   Many operators match those in C.


 /// Cast Operator
//
//   Used to convert one data type to another.
//
//   :Syntax: TYPE'(EXPRESSION)
//   EXPRESSION is converted to TYPE
//   C Equivalent:  ((TYPE)EXPRESSION)



 /// Slicing Operators
//
//   :Syntax: ARRAY[ POS +: WIDTH ]
//
//    POS: An integer expression.
//    WIDTH: A constant integer expression.
//
//    Returns at array of elements:
//        { ARRAY[POS], ARRAY[POS+1], ..., ARRAY[POS+WIDTH-1] }
//
//   :Syntax: ARRAY[ POS -: WIDTH ]
//    Similar.




////////////////////////////////////////////////////////////////////////////////
/// Floating Point Data Types
///

// :SV12: Section 6.12

 /// Floating Point Types
 //
 // :Keyword: real      - C double (usually IEEE 754 double, 64 bits).
 // :Keyword: shortreal - C float  (usually IEEE 754 single, 32 bits).

 /// Uses
 //
 //  Use them in testbench code, for example, to compute percentages.
 //
 //  Cannot be used with net type objects.
 //
 //  Do not use them when describing hardware ...
 //  ... because synthesis programs (at least now AFAIK) won't accept them.

 /// Punning Functions
 //
 // :Keyword:  $realtobits
 // :Keyword:  $shortrealtobits
 // :Keyword:  $bitstoreal
 // :Keyword:  $bitstoshortreal
 //
 // The functions above *do not* convert or otherwise change the
 // underlying data, they simply return the same data as a new data
 // type.
 //
 // To understand the statement above remind yourself of the difference
 // between a number and the number's many possible representations.



// :Example:
//
// Code showing use of FP types and conversion functions.

module fp_examples;

   // The declaration below would be an error since it's using a net type,
   // and reals can only be declared as variables.
   //
   // uwire real rw;

   real d, from_dbits, from_dval;
   logic [63:0] dbits;
   logic [63:0] dval;

   initial begin

      // The 64 bits of d are set to the FP double-precision
      // representation of 3.4 based on the IEEE 754 standard.
      //
      d = 3.4;

      // Implicit cast of d's value (a real) to dval's type
      // (logic). The 64 bits of dval are set to 3 in an ordinary
      // binary representatin.
      //
      dval = d;   // dval -> 3

      // Underlying representation not changed.
      //
      dbits = $realtobits( d );
      //
      // Now d and dbits are bit-for-bit identical, both are 3.4
      // represented as an IEEE 754 double.

      $write("d %.20f  dval 0x%4h,  dbits 0x%h\n", d, dval, dbits);

      // Display Output:
      //
      // d 3.39999999999999991118  dval 0x0003,  dbits 0x400b333333333333

      dval = dval + 1;    // This works because dval has an integer.

      // The addition below won't work as expected because Verilog
      // will use integer addition (since the type is logic) while the
      // underlying representation is floating-point.
      //
      dbits = dbits + 1;

      // Change type back to logic without changing underlying data.
      //
      from_dbits = $bitstoreal( dbits ) + 1;

      // Display Output:
      //
      // After +1: from_dbits 3.40000000000000035527  dval 0x0004,  dbits 0x400b333333333334

      $display("After +1: from_dbits %.20f  dval 0x%4h,  dbits 0x%h\n",
               from_dbits, dval, dbits);

   end

endmodule


// :Example:
//
// FP adder module and testbench. The testbench shows how to use FP
// types correctly. The adder itself abuses them. (The next example
// corrects the problem.)

// Adder module, bad because it is probably not synthesizable due to
// using floating-point type (shortreal here).
//
module my_adder_bad(output shortreal sum, input shortreal a, b);

   assign sum = a + b;

endmodule

// Testbench. The testbench code is good, it's the adder that's bad.
//
module real_demo_bad();

   // Module inputs and outputs.
   //
   shortreal a, b, sum;

   // Adder is bad because it uses a FP type for arguments.
   //
   my_adder_bad a1(sum,a,b);

   localparam int num_tests = 10;

   initial begin

      // Compute 1.0 / 2^{32}, used to prepare a random number
      // in the range (-0.5,0.5).
      //
      real scale;
      scale = 1.0 / ( longint'(1) << 32 );
      //
      // Note: Expression above uses cast operator: TYPE'(EXPR).
      //       In this case 1 is converted to a long int.

      for ( int i=0; i<num_tests; i++ ) begin

         a = {$random} * scale;  // Values should be in range [0,1]
         b =  $random  * scale;  // Values should be in range [-0.5,0.5]
         #1;
         $display("Sum is %f + %f = %f\n",a,b,sum);

      end

   end

endmodule


// :Example:
//
// Example showing FP numbers in synthesizable hardware.
// This example uses components from the Cadence ChipWare library.

// Adder module using a Cadence-supplied FP adder module.
//
module my_adder_good(output logic [31:0] sum, input logic [31:0] a, b);

   // Adder module has a rounding mode input. Set it to 0.
   //
   localparam logic [2:0] rounding_mode = 0;

   // Adder module has a status output. Leave it unconnected.
   //
   uwire logic [7:0] status; // Unused.

   CW_fp_add chip_ware_adder
     (.a(a), .b (b), .rnd (rounding_mode), .z (sum), .status (status));

endmodule


// Testbench for good adder.
//
module real_demo_good();

   logic [31:0] ai, bi;
   uwire logic [31:0] sumi;

   my_adder_good a1(sumi,ai,bi);

   localparam int num_tests = 10;

   initial begin

      automatic real scale = 1.0 / ( longint'(1) << 32 );

      for ( int i=0; i<num_tests; i++ ) begin

         shortreal a, b, sum;

         a = $random * scale;
         b = $random * scale;

         // Change type from shortreal to logic.
         //
         ai = $shortrealtobits(a);
         bi = $shortrealtobits(b);

         #1;

         // Change type from logic to shortreal.
         //
         sum = $bitstoshortreal(sumi);

         $display("Sum is %f + %f = %f\n",a,b,sum);

      end

   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Net Object Types

// :SV12: Section 6.6

//  Used to interconnect devices.
//  Do not store values.

//  Can NOT ordinarily be assigned in procedural code.
//  Net types are assigned by:
//   Connecting them to the output of a module (in an instantiation).
//   Using an assignment statement (to be covered).
//   Assigning in the declaration.

// Some net types:
//
//  :Keyword: uwire: for ordinary connections, single driver.
//  :Keyword: wire:  for ordinary connections, any number of drivers.
//  :Keyword: tri:   for tri-state logic. (E.g., for busses.)
//  :Keyword: wand:  for wired and connections
//  :Keyword: wor:   for wired or connections.
//
//  See :SV12: Table 6-1 for the full list.
//
//  In this class we will just use uwire.

module net_demo(output wire x, input wire a,b);

   wire wire_1;
   uwire wire_2;
   logic r1;

   // Example of a continuous assignment.
   assign wire_1 = a | b;

   and a1(wire_2,a,b);

   // This is a continuous assignment, NOT an initialization.
   wire   wire_3 = wire_1 ^ r1;

   // Wired and example.  wire_5 = (a | b ) & !wire_2
   wand   wire_5;
   assign wire_5 = a | b;
   assign wire_5 = !wire_2;

   wire   wire_4;

   always @( a or b ) begin
      r1 = a;

      // wire_4 = b; // Not allowed.

   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Vectors and other Packed Arrays, Unpacked Arrays
///

// :SV12: 6.9
// :SV12: 7.4 Packed and unpacked arrays.

// :Def: Unpacked Array
//       An ordinary array, can have any number of dimensions and
//       elements can be of any type.
//
//       Uses: The usual (no different than the uses for arrays in
//       other languages).

// :Def: Vector
//       A one-dimensional array which as a whole can be treated as an
//       integer, but which can also be treated as an array of
//       bits.
//
//       Uses: Modeling a bunch of wires that collectively hold an
//       integer, or any other collection conveniently treated as a
//       unit.

// :Def: Packed Array
//       A multi-dimensional array which as a whole can be treated as
//       an integer, but which can also be treated as a
//       multidimensional array of (usually) bits.
//
//       Uses: The same as a vector, with more indexing flexibility,
//       for example, organizing a 32-bit object into 4 8-bit quantities.

 /// Vectors and Packed Arrays
//
//   Element data type must be: bit, logic, or an enumerated type.
//
//   Dimension sizes declared before the variable name.
//
//   A one dimensional packed array is called a vector.
//
// :Example:  logic [39:0] vector1;       // 1D packed, aka, vector.
// :Example:  logic [9:0][3:0] vector2;   // 2D packed.

 /// Unpacked Arrays
//
//   Any element type, including a packed array.
//
//   Address ranges (dimension sizes) declared after the variable name.
//
//   :Example: real values[100];


// :Example:
//
// Three ways of declaring a 40-bit variable: as a vector, a 2-dimensional
// packed array, and as a 1-dimensional unpacked array.

module v_etc();

   logic [39:0] vector1;      // A 40-bit variable.
   logic [9:0][3:0] vector2;  // A 40-bit variable organized as 10 groups of 4.
   logic unpacked3[39:0];     // 40 1-bit variables.

   initial begin

      // Conveniently assign vector types in one step.
      //
      vector1 = 40'h123456789a;
      vector2 = vector1;

      /// Can operate on packed array as though it were an integer.
      //
      // Operate on entire vector.
      //
      vector2 = vector2 + 1;  // LSD changes from a to b.

      // Operate only on a 4-bit slice.
      //
      vector2[1] += 3;        // Hex digit 1 changes from 9 to c.

      // Operate on a bit.
      //
      vector2[2][0] = 1;      // Hex digit 2 changes from 8 to 9.

      // Not allowed. (Needs a streaming operator, >>)
      //
      // unpacked3 = vector1;

      // Initialize the unpacked array.
      //
      for ( int p = 0; p < $bits(vector1); p++ ) unpacked3[p] = vector1[p];

      for ( int b = 0;  b < 10;  b++ ) begin

         logic [3:0] nib1, nib2, nib3, nib4; // nib is for nibble.

         nib1 = vector1[ b*4 +: 4 ];  // Bits b*4 to b*4+3.

         nib2 = vector2[ b ];

         nib3 = { unpacked3[ b*4 + 3 ], unpacked3[ b*4 + 2 ],
                  unpacked3[ b*4 + 1 ], unpacked3[ b*4 + 0 ] };

         $display
           ("Nibble %d is  %h or %h or %h or %h\n",
            b, nib1, nib2, nib3, nib4);

      end

   end


endmodule




//////////////////////////////////////////////////////////////////////////////
/// Address Ranges in Declarations
///

//
 ///   :Syntax: TYPE ARRAY_NAME[ADDRESS_RANGE];
//
//     Address range determines valid element numbers for an array.
//
//     Address range also indicates type of array.
//
 ///   Possible address ranges:
//
 ///     Static Arrays, positive integer.
//     Synthesizable.
//
//      :Example: int a[4];
//       Valid indices: 0, 1, 2, 3
//
//      :Example: int a[S];
//       Valid indices are: 0, 1, ..., S - 1
//
//
 ///     Static Arrays: Range.
//     Synthesizable.
//
//      :Example: int a[10:8];
//       Valid indices: 10, 9, 8.
//       In other words, a[9] is okay, but a[7] is out of range.
//
//      :Syntax: LAST:FIRST
//       Element indices are FIRST, FIRST+1, ..., LAST
//
//
 ///     Dynamic Arrays
//     Not (easily) synthesizable.
//
//       Array size is determined at run time.
//
//       :Syntax: ELEMENT_TYPE ARRAY_NAME[];
//
//      :Example: int a[];  a = new[size];  // Use new to allocate elts.
//       Variable size known only at run time.
//
//       See :SV12: Section 7.5
//
 ///     Associative Arrays
//     Not (easily) synthesizable.
//
//       Index set determined by type.
//
//       :Syntax: ELEMENT_TYPE ARRAY_NAME[INDEX_TYPE];
//
//       :Example: int a[ string ];
//        Index can be any string.
//
//       :Example: int a[ integer ];
//        Index can be any integer.
//
//       :Example: int a[ real ];
//        Index can be any real number. (Really.)
//        Unlike other (non-associative) arrays, storage for elements
//         is allocated as new indices are encountered.


// :Example:
//
// Example of use of different ranges.

module range_examples(input int num_elts);

   logic [7:0] array1[];        // Dynamically sized.
   logic [7:0] array2[string];  // Associative. (string is a data type)
   int array3[10];              // Ten elements, indices 0..9
   int array4[10:1];            // Ten elements, indices 1..10

   //   string      step[real];  // ALAS, not yet implemented.

   initial begin

      array1 = new [ num_elts ];

      // Hope that num_elts >= 6.
      //
      array1[ 5 ] = 123;

      array2[ "5" ] = 1;
      array2[ "five" ] = 2;

      for ( int i=0; i<10; i++ ) array3[i] = i;

      // Perfectly fine, same size and type.
      //
      // It doesn't matter that index numbering different.
      //
      array4 = array3;

`ifdef REAL_INDICES
      step[1] = "Unlock door.";
      step[2] = "Enter room.";
      step[3] = "Sit down.";
      step[1.5] = "Turn off alarm.";
`endif

   end

endmodule


 /// Dynamic Arrays
//
//   :SV12: 7.5
//
//   :Keyword: new[NUM_ELTS](init)  --
//   :Keyword: size() -- Member function, return number of elements.
//   :Keyword: delete() -- Member function, delete all element.

 /// Associative Arrays
//
//   :SV12: 7.8
//
//   :Keyword: num() -- Member function, number of elements.
//   :Keyword: size() -- Member function, number of elements.
//   :Keyword: delete() -- Member function, delete all entries.
//   :Keyword: delete(INDEX) -- Member function, delete entry INDEX.
//   :Keyword: exists(INDEX) -- Member function, return 1 if INDEX in array.

 /// The foreach Looping Construct
//
//   :Keyword: foreach -- Loop over elements of array or other container.
//
//   :Syntax: foreach ( ARRAY[IVAR] ) STATEMENT
//    Execute statement for each element of ARRAY setting IVAR to
//    the element's index. IVAR is a new variable (it should not be declared).
//
//   :Example: foreach ( a[i] ) b[i] = a[i];
//





 /// Other Topics
//
//  Streaming operators.
//    { << 4 { packed_expr } }




/// Vectored and Scalared Declaration Modifiers

//  LRM 3.3 (At end of section.)

//  The *vectored* keyword modifies a net declaration, informing
//  the compiler that one cannot look at individual bits of a
//  net.

module vector_examples2();

   // Range specification examples.

   wire  [0:31] a;  // Can examine bits.
   wire scalared [0:31] b;  // Equivalent to above, can examine bits.
   wire vectored [0:31] c;  // Shouldn't examine bits.

   wire       a_is_odd = a[31];  // Works
   wire       b_is_odd = b[31];  // Works
   wire       c_is_odd = c[31];  // Error on some compilers, not Modelsim.

endmodule // vector_examples



`include "/apps/linux/cadence/RC142/share/synth/lib/chipware/sim/verilog/CW/CW_fp_add.v"