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

/// Contents

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

/// References

// :SV17: IEEE 1800-2017 -- The SystemVerilog Standard
//        https://ieeexplore.ieee.org/document/8299595/
//        This is for those already familiar with Verilog.
//
// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//        The text used in LSU EE 2740.


////////////////////////////////////////////////////////////////////////////////
/// Identifiers and Whitespace

//  :SV12: Chapter 5

 /// 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 this$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;
   // See: https://xkcd.com/1963/

   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

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

 /// Two Kinds of Objects :  Nets and Variables

 // :Def: Kind
 // A classification of objects. The two kinds are: nets and variables.

 /// Nets
 //
 //  :Sample: uwire [7:0] i_am_a_net;
 //  :Sample: uwire logic [7:0] i_am_a_net;
 //
 //  Are used to model connections between devices.
 //
 //  Usually get values by being /driven/, meaning connected to something ...
 //  ... they are not normally assigned to.
 //
 //  The are the default kind for module ports.
 //
 /// Net Kind Types
 //
 //  :Keywords: uwire,wire,tri,wand,wor,triand,trior,trireg, ..
 //  Declaration of a net kind usually starts with one of these types.
 //  
 //  Some of these are described in detail in the Net Object Kinds section.
 //
 //  In class the only net type we will willingly use is uwire.
 //  Older Verilog and tools may use wire.
 //

 /// Variables
 //
 //  :Sample: var logic [7:0] i_am_a_variable;
 //  :Sample: logic [7:0] i_am_a_variable;
 //  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);

   // The declarations below include both a kind (var,wire) ..
   // .. and a type (int,logic).
   //
   var int my_var;
   wire logic my_net, my_other_net;
   wire logic [7:0] my_8b_net;
   uwire logic my_safe_net, my_other_safe_net;
   var  logic my_other_var;

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

   assign my_net = a[0];   // This is a driver, driving my_net.

   // The output of inst_name is a driver, driving my_other_net.
   some_module inst_name(my_8b_net,a);

   initial begin

      // my_net = 1;  // Would be an error if not commented out.
      my_var = 3;  // This is an assignment.
      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_sv;  // 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_other_var_2 = a;   // Okay, can assign to variables.
        // my_wire = 13;      // Error because can't assign wires.
     end

   some_module sm( my_wire, my_var[7:0] ); // 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

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

 // :Keyword: logic    -  1-bit, unsigned, 4-state    -- Often used
 // :Keyword: integer  - 32-bit,   signed, 4-state    -- Legacy, don't use.
 // :Keyword: time     - 64-bit, unsigned, 4-state    -- Legacy, don't use.

 // 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.
 //
 /// But, what are they?
 //
 //  First, if all bits are 0 or 1 (none are x or z), then
 //   the ordinary rules apply, including the rules for integer
 //   arithmetic.
 //
 //  Second, think about them as arrays, where each array element
 //   is either 0, 1, x, z. Don't think about values as numbers.
 //  Operations are defined on these four values. For example:
 //    1 & 1 = 1,  (0 and 1 work in the usual way)
 //    1 & x = x,  0 & x = 0, ...
 //    1 | x = 1,  0 | x = x, ...
 //    :SV12: See 11.4.8 for tables defining some operations on 4-bit types.

 /// Integer Four-State Comparison Operators
 //
 //  Ordinary comparison:  ==, !=,  >,   >=, <, <=
 //  - If either operand is x in any bit, the result is x.
 //
 //  Four-state compare:  ===, !==, ==?, !=?

 //  :Keyword: ===,!==
 //  To be equal each element must be identical.
 //  :Example:  2'b0x === 2'b0x  is true.
 //  :Example:  2'b0x === 2'b00  is false.
 //  :Example:  2'b0x === 2'b0z  is false.
 //  :Example:  2'b0z === 2'b0z  is true.
 //
 //  :Keyword: ==?,!=?
 //  The x and z values act as wildcard (don't care) values.
 //  :Example:  2'b0x ==? 2'b0x  is true. 
 //  :Example:  2'b0x ==? 2'b00  is true. 
 //  :Example:  2'b0x ==? 2'b01  is true. 
 //  :Example:  2'b0x ==? 2'b10  is false.


 /// 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.      -- Often used.
 // :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.


 /// Signed and Unsigned Qualifiers.
 //
 //  Can be used to modify 2- and 4-state integer types.
 //
 //  See max_mod for an example of where correct use of signed and
 //  unsigned. is important.

 // :Keyword: signed
 // :Keyword: unsigned
 // :Sample: logic signed [7:0] a;
 // :Sample: int unsigned b;

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


module int_types;

   int a_int, b_int, c_int;
   bit [31:0] a_bit, b_bit, c_bit;  // Similar to int, but unsigned.
   logic [31:0] a_logic, b_logic, c_logic;

   initial begin

      // Bit values are either 0 or 1, no x's or z's here.
      // Therefore arithmetic and logical operators have their usual meaning.
      //
      a_logic = 123;
      b_logic = 555;
      c_logic = a_logic + b_logic;

      $write("Logic types: (shown in decimal)\n   %4d\n + %4d\n = %4d\n",
             a_logic, b_logic, c_logic);
      $write("Logic types: (shown in hexadecimal)\n   %4h\n + %4h\n = %4h\n",
             a_logic, b_logic, c_logic);
      $write("Logic types: (shown in binary)\n   %16b\n + %16b\n = %16b\n",
             a_logic, b_logic, c_logic);

      // Logic types: (shown in decimal)
      //     123
      //  +  555
      //  =  678
      // Logic types: (shown in hexadecimal)
      //    007b
      //  + 022b
      //  = 02a6
      // Logic types: (shown in binary)
      //    0000000001111011
      //  + 0000001000101011
      //  = 0000001010100110


      // Bits assigned all four values, 0, 1, x, z.
      // Result of arithmetic is x if any bit is x or z. (Even x*0, x-x.)
      // Result of bitwise logical operation on a bit
      // .. is 0 or 1 if x doesn't matter, as in x && 0 = 0.
      //
      a_logic = 32'b00001111xxxxzzzz;
      b_logic = 32'b01xz01xz01xz01xz;

      c_logic = a_logic + b_logic;
      $write("Logic types:\n   %16b\n + %16b\n = %16b\n",
             a_logic, b_logic, c_logic);
      //
      //    00001111xxxxzzzz  a_logic
      //  + 01xz01xz01xz01xz  b_logic
      //  = xxxxxxxxxxxxxxxx  c_logic: All bits x because of arithmetic op.


      c_logic = a_logic & b_logic;
      $write("Logic types:\n   %16b\n & %16b\n = %16b\n",
             a_logic, b_logic, c_logic);
      //
      //    00001111xxxxzzzz  a_logic
      //  & 01xz01xz01xz01xz  b_logic
      //  = 000001xx0xxx0xxx  c_logic: "& 0" operation changes x or z to 0.


      c_logic = a_logic | b_logic;
      $write("Logic types:\n   %16b\n | %16b\n = %16b\n",
             a_logic, b_logic, c_logic);
      //
      //    00001111xxxxzzzz  a_logic
      //  | 01xz01xz01xz01xz  b_logic
      //  = 01xx1111x1xxx1xx  c_logic: "| 1" operation changes x or z to 1.


      // With two-state types, x and z in literals are changed to 0.
      //
      a_int = 32'b00001111xxxxzzzz;
      b_int = 32'b01xz01xz01xz01xz;

      c_int = a_int + b_int;
      $write("Int types:\n   %16b\n + %16b\n = %16b\n", a_int, b_int, c_int);
      //
      //    0000111100000000  a_int
      //  + 0100010001000100  b_int
      //  = 0101001101000100

      c_int = a_int & b_int;
      $write("Int types:\n   %16b\n & %16b\n = %16b\n", a_int, b_int, c_int);
      //
      //    0000111100000000
      //  & 0100010001000100
      //  = 0000010000000000

      c_int = a_int | b_int;
      $write("Int types:\n   %16b\n | %16b\n = %16b\n", a_int, b_int, c_int);
      //
      //    0000111100000000
      //  | 0100010001000100
      //  = 0100111101000100

   end

endmodule



// :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_mod 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;
         //
         // It would also be okay to make shadow_max logic signed [7:0].

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

         shadow_max = a >= b ? a : b;

         #1;

         if ( shadow_max !== m )
           $write("Wrong result  max(%d,%d)  %d != %d (correct)\n",
                  a, b, m, shadow_max);
         //
         // Note: use of !== instead of != is important here ..
         // .. because !== returns either true (correct) or false (wrong) ..
         // .. whereas != might return x due to an x or z in m.
      end

      $write("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_mod 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 )
           $write("Different result  max(%d,%d)  %d != %d (correct)\n",
                  a, b, m, shadow_max);
      end

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

   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.
//
// :Sample:  logic [39:0] vector1;       // 1D packed, aka, vector.
// :Sample:  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.
//
//   :Sample: 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 unpacked3[39:0];     // 40 1-bit variables.
   logic [9:0][3:0] vector2;  // A 40-bit variable organized as 10 groups of 4b.

   initial begin

      // Conveniently assign vector types in one step.
      //
      vector1 = 40'h123456789a;
      vector2 = vector1;
      unpacked3[0] = 1'b0;
      unpacked3[1] = 1'b1;
      unpacked3[2] = 1'b0;
      // ... twenty minutes later ..
      unpacked3[39] = 1'b0;

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

      // Operate only on a 4-bit slice.
      //
      vector2[0] += 1;        // Hex digit 0 changes from a to b.
      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. (Could copy with 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 ] };

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

      end

   end


   /// Examples of both packed and unpacked dimensions.
   //
   //      c    e                  a    b
   logic [9:0][3:0] vector_2d_2d[19:0][2:0];
   logic [9:0][3:0] vector_2d_1d[2:0];
   logic [9:0][3:0] vector_2d;
   logic [3:0] nib;
   logic b;

   initial begin

      //                          a
      vector_2d_1d = vector_2d_2d[11]; // Evaluates to 3-element unpacked.

      //           a   b
      vector_2d_2d[11][2] = 40'habcd;  // Write a 40-bit quantity.

      //                       a   b
      vector_2d = vector_2d_2d[11][1];

      //                 a   b  c
      nib = vector_2d_2d[11][1][9];    // Evaluates to 4-bit vector.

      //               a   b  c  e
      b = vector_2d_2d[11][1][9][2];   // Evaluates to one bit.

      vector_2d_1d[2] = 40'hef01;

   end


endmodule




////////////////////////////////////////////////////////////////////////////////
/// Some More 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)
//   :Sample:   real'(an_int+5)
//
//   :Syntax: WID'(EXPRESSION)
//   WID is a positive constant integer expression
//   EXPRESSION is a packed vector.
//   The width of EXPRESSION is changed to WID.
//   :Sample:  10'(some_12_bit_packed_vector)

//   :Syntax: signed'(EXPRESSION)
//   :Syntax: unsigned'(EXPRESSION)
//   EXPRESSION is an integer type. (bit, logic, shortint, ...)
//   The signedness of EXPRESSION is changed as indicated.
//
 /// Note:
//
//   Don't forget the parentheses around EXPRESSION, they are part
//   of the cast operator.


// :Example:
//
// Use the cast operator to widen the a+b expression to 8 bits so that
// it will not overflow.

module less_than
  ( output uwire lt, input uwire [6:0] a, b, amt );

   assign lt = 8'(a + b) < amt;

endmodule


 /// Slicing Operators
//
//   :Syntax: ARRAY[ MSB_IDX : LSB_IDX ]
//   :Syntax: ARRAY[ POS +: WIDTH ]
//   :Sample: ARRAY[ POS+WIDTH-1 : POS ]
//
//    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.



////////////////////////////////////////////////////////////////////////////////
/// Binary Floating-Point Representation and Arithmetic
//
 /// Binary Floating-Point (FP) Representations
//
// The floating-point (FP) representations in this section (before
// IEEE 754) are NOT computer representations.
//
// Among other things, that means the number of bits needed to store a
// number is not specified.
//
// Computer representations for FP numbers covered in the next section,
// IEEE 754.


 /// Binary Fixed Point Representation
//
//
// Each digit position has a multiplier.
//
//
// FiP Binary Number: 1  0  1  0  1. 1   0   0   1
// Digit Position:    4  3  2  1  0 -1  -2  -3  -4
// Multiplier:       16  8  4  2  1 1/2 1/4 1/8 1/16
//
// Value of number:  1*16 + 0*8 + 1*4 + 0*2 + 1*1 + 1/2 + 0/4 + 0/8 + 1/16
//                   = 21.5625
//
// Other Examples:
//
//     1.1    = 1.5
//     1.01   = 1.25
//     1.11   = 1.75
//     1.001  = 1.125
//  1111.1111 = 15.9375
//
//
// Fixed Point Decimal to Binary Conversion
//
//   To convert decimal number x,  0 < x < 1.
//
//   Method 1:
//
//     For digit position -1:
//        if x >= 1/2, digit is 1,  x = x - 1/2;
//        if x <  1/2, digit is 0,  x unchanged.
//     For digit position -2:
//        if x >= 1/4, digit is 1,  x = x - 1/4
//        if x <  1/4, digit is 0,  x unchanged.
//     Etc.
//
//   Method 2:
//
//     Let r be the number of digits past decimal point desired.
//
//     Convert x * 2^r to binary.
//
//     MSB is first digit past binary point, etc.
//
//     Example:
//       r = 4,  x = .75
//       Convert .75 * 2^4 = 12 to binary: 1100
//       x in binary is: .1100
//
// Examples to 12 digits:
//
//  1.1 = 1.000110011001...     1.1 * 2^12 = 4505 = 1000110011001
//  1.2 = 1.001100110011...
//  1.3 = 1.010011001100...
//  1.4 = 1.011001100110...
//  1.5 = 1.1
//
// Note:
//
// Common decimal numbers such as 0.2 do not have exact binary representations.


 /// Binary Scientific Notation
//
// Binary Scientific Representation Similar to Decimal Scientific Notation
//
//  Decimal: SIGN SIGNIFICAND x 10^{EXPONENT}
//  Binary:  SIGN SIGNIFICAND x 2^{EXPONENT}
//
//  Decimal Examples:
//
//    1.23 x 10^{2}  = 123
//    1.23 x 10^{0}  = 1.23
//    1.23 x 10^{-1} = .123
//    Examples above are normalized, examples below are not.
//    12.3 x 10^{1}  = 123
//    .123 x 10^{1}  = 1.23
//    123 x 10^{-3}  = .123
//
//  Binary Examples
//
//    1 x 2^{0}    = 1 = 1
//    1 x 2^{1}    = 10 = 2
//    1 x 2^{2}    = 100 = 4
//    1.1 x 2^{2}  = 110 = 6
//    1.1 x 2^{1}  = 11 = 3
//    1.1 x 2^{0}  = 1.1 = 1.5
//    1.1 x 2^{-1} = .11 = .75
//    Examples above are normalized, examples below are not.
//    11 x 2^{1}   = 110 = 6
//    11 x 2^{0}   = 11 = 3
//    11 x 2^{-1}  = 1.1 = 1.5
//    11 x 2^{-2}  = .11 = .75


 /// Addition Using Scientific Notation
//
// Consider:
//
//   a_scand x 2^{a_exp}
//   b_scand x 2^{b_exp}
//
//   Assume that a > b in magnitude. (That is, |a| > |b|.)
//
//   To add:
//
//     Set b'_exp = a_exp.
//
//     Set b'scand = b_scand / 2^(a_exp - b_exp)
//       That is, right-shift b_scand by (a_exp - b_exp) bits.
//
//       Note that:  b_scand x 2^{b_exp} == b'_scand x 2^{b'_exp}
//
//     Set s_scand = a_scand + b'_scand
//
//     Set s_exp = a_exp
//
//     We now have the sum: s_scand x 2^{s_exp}


// :Example:
//
//  Multiply:
//    a = 1.1 x 2^4
//    b = 1.0 x 2^3
//
//    a_scand -> 1.1,  a_exp -> 4
//    b_scand -> 1.0,  b_exp -> 3
//
//  Step 1: Scale b so its exponent, 3, matches b's, 4.
//
//    b = 1.0 x 2^3 = 0.1 x 2^4
//
//    b'_scand => 0.1, b'_exp = 4
//
//  Step 2: Add significands.
//
//    a_scand + b'_scand = 1.1 + 0.1 = 10.0
//
//    a+b = 10.0 x 2^4
//
//  Step 3: Normalize the number (optional)
//
//    a + b  =  10.0 x 2^4  =  1.0 x 2^5
//
//    Answer is: 1.0 x 2^5
//
// Subtraction is similar.


 /// Multiplication Using Scientific Notation
//
// Consider:
//
//   a_scand x 2^{a_exp}
//   b_scand x 2^{b_exp}
//
//   To multiply these:
//
//     Set p_scand = a_scand x b_scand
//     Set p_exp = a_exp + b_exp
//     Optional: Normalize p
//
//     Product is p_scand x 2^{p_exp}

// :Example:
//
//  a = 1.1 x 2^4
//  b = 1.0 x 2^3
//
//  Step 1: Multiply significands and add exponents.
//
//    p_scand  =  a_scand * b_scand  =  1.0 * 1.1  =  1.1
//    p_exp    =  a_exp + b_exp      =  4+3        =  7
//
//    a * b = 1.1 x 2^7
//
//  Step 2: Normalize the number.
//
//    In this case result is already normal.
//
//    a * b = 1.1 x 2^7



////////////////////////////////////////////////////////////////////////////////
/// IEEE 754 FP Standard

// :PH: 3.5

 /// Standard Specifies
//
// Formats of FP numbers. (There are several sizes.)
// Results of arithmetic operations, including rounding.

 /// Objectives of Standard
//
// Represent range of numbers in common use. (Of course.)
// Predictable rounding behavior.
// Compare as integers.
//
// The following is NOT an objective:
//
// Keep things simple for an introductory computer class.
// Nevertheless, it's not that bad.

 /// Features
//
// Can Represent:
//   Floating-point number.
//   + and - Infinity, and other special values.
//
// Special Properties
//   Representation of positive zero is all zeros.
//   Can use signed integer magnitude and equality tests.

 /// Sizes
//
// Half:   16 bits. Called FP16.  Not the same as BP16.
// Single: 32 bits.
// Double: 64 bits.
// Extended: Varies, not shown here.

 /// Key Ideas
//
// Format Specifies:
//
//  Sign.
//  Exponent.
//  Significand (Fraction)
//
// Slight Complications (but for good reason):
//
//  Exponent is biased.
//  Significand usually omits the MSB (it's assumed to be 1).


 /// IEEE 754 Single Format
//
// Format:   SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
// 31:    S: Sign bit: 1 negative, 0 positive.
// 30-23: E: Biased Exponent. (Exponent is E-127)
// 22-0:  F: Significand (Fraction)
//
//  Case                    Value formula.
//  0 < E < 255,  S = 0  :    ( 1.0 + F / 2^{23} ) 2^{E-127}
//  0 < E < 255,  S = 1  :  - ( 1.0 + F / 2^{23} ) 2^{E-127}
//  E = 0, S = 0, F = 0  :    0
//  E = 0, S = 1, F = 0  :  - 0
//  E = 255, S = 0, F = 0:    Infinity
//  E = 255, S = 1, F = 0:  - Infinity

 /// IEEE 754 Double Format
//
// Format:   SEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
// 63:    S: Sign bit: 1 negative, 0 positive.
// 62-52: E: Biased Exponent. (Exponent is E-1023)
// 51-0:  F: Significand (Fraction)
//
//  Case                      Value formula.
//  0 < E < 1023,  S = 0   :    ( 1.0 + F / 2^{23} ) 2^{E-1023}
//  0 < E < 1023,  S = 1   :  - ( 1.0 + F / 2^{23} ) 2^{E-1023}
//  E = 0, S = 0, F = 0    :    0
//  E = 0, S = 1, F = 0    :  - 0
//  E = 1023, S = 0, F = 0 :    Infinity
//  E = 1023, S = 1, F = 0 :  - Infinity

 /// IEEE 754 Rounding Modes
//
// Format specifies four rounding modes.
// Hardware set to use desired rounding mode.
//
// Rounding Modes:
//
//  Round to even. (Nearest LSB zero.)  Most popular.
//  Round towards zero.
//  Round towards infinity.
//  Round towards -infinity.


 /// IEEE 754 Single Format Examples:   IEEE 754 to Value
//
// Single FP:   32h'3fc00000
//            = 32b'00111111110000000000000000000000
//                  SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
//
//                  0 01111111 10000000000000000000000
//                  S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
//
//                  S = 0,  E = 0x7f = 127,  F 0x400000 = 4194304
//
// Based on value of S and E, the following case applies:
//
//  0 < E < 255,  S = 0  :    ( 1.0 + F / 2^{23} ) 2^{E-127}
//
//  Value = ( 1.0 + 4194304 / 2^{23} ) 2^{127-127}
//        = ( 1.0 + 0.5 )
//        = 1.5

// Single FP:   32h'456ab000
//            = 32b'01000101011010101011000000000000
//                  SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
//
//                  0 10001010 11010101011000000000000
//                  S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
//
//                  S = 0,  E = 8a = 138,  F 6ab000 = 6991872
//
// Based on value of S and E, the following case applies:
//
//  0 < E < 255,  S = 0  :    ( 1.0 + F / 2^{23} ) 2^{E-127}
//
//  Value = ( 1.0 + 6991872 / 2^{23} ) 2^{138-127}
//        = ( 1.0 + 0.833496 ) 2048
//        = 3755

// Single FP:   32h'c0490fdb
//            = 32b'11000000010010010000111111011011
//                  SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
//
//                  1 10000000 10010010000111111011011
//                  S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
//
//                  S = 1,  E = 80 = 128,  F 490fdb = 4788187
//
// Based on value of S and E, the following case applies:
//
//  0 < E < 255,  S = 1  :  - ( 1.0 + F / 2^{23} ) 2^{E-127}
//
//  Value = - ( 1.0 + 4788187 / 2^{23} ) 2^{128-127}
//        = - ( 1.0 + 0.570796 ) 2
//        = -3.14159

// Single FP:   32h'0
//            = 32b'00000000000000000000000000000000
//                  SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
//
//                  0 00000000 00000000000000000000000
//                  S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
//
//                  S = 0,  E = 0,  F = 0
//
// Based on value of S and E, the following case applies:
//
//  E = 0, S = 0, F = 0  :    0
//
//  Value = 0

// Single FP:   32h'7f800000
//            = 32b'01111111100000000000000000000000
//                  SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
//
//                  0 11111111 00000000000000000000000
//                  S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
//
//                  S = 0,  E = 255,  F = 0
//
// Based on value of S and E, the following case applies:
//
//  E = 255, S = 0, F = 0:    Infinity
//
//  Value = Infinity.

 /// IEEE 754 Single Format Examples:   Value to IEEE 754
//
// Value (decimal):        12.75
//   Convert to binary:  1100.11
//   Convert to normalized binary scientific notation:  1.10011 x 2^3
//
//   S = 0  (it's positive)
//   E = 127 + 3 = 130 = 100 0010
//   F = 10011 000000000000000000
//
//   Single: 0  1000 0010  10011 000000000000000000
//         = 0100 0001 0100 1100 0000 0000 0000 0000
//         = 0x414c0000



////////////////////////////////////////////////////////////////////////////////
/// 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 in class assignments ...
 //  ... because our synthesis programs won't accept them.

 /// Punning Functions
 //
 // :Keyword:  $realtobits
 // :Keyword:  $bitstoreal
 // :Keyword:  $shortrealtobits
 // :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.

 /// :Practice Problems:
 //
 //  2017 Homework 2 -- Use ChipWare modules to perform linear interpolation.
 //    https://www.ece.lsu.edu/v/2017/hw02.pdf
 //    https://www.ece.lsu.edu/v/2017/hw02.v.html
 //    https://www.ece.lsu.edu/v/2017/hw02-sol.v.html
 //
 //  2017 Midterm Exam Problem 6c -- Synthesizability of reals.
 //    https://www.ece.lsu.edu/v/2017/mt.pdf
 //    https://www.ece.lsu.edu/v/2017/mt_sol.pdf
 //
 //  2018 Homework 3 Problem 2 -- Sorting network operating on FP keys.
 //    https://www.ece.lsu.edu/v/2018/hw03.pdf
 //    https://www.ece.lsu.edu/v/2018/hw03-sol.v.html



// :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 nets can only be declared using four-value integer types.
   //
   // 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 representation.
      //
      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 );

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

      $write("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;
         $write("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 uwire [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);

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

      end

   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Net Object Kinds

// :SV12: Section 6.6

//  Used to interconnect devices.
//  Net objects are driven, they are not assigned.
//
//  Can NOT ordinarily be assigned in procedural code.
//  Net types are driven by:
//   Connecting them to the output of a module (in an instantiation).
//   Using an assign statement (to be covered).
//   Assigning in the declaration.
//
//  The default type for an object of a net kind is logic.
//  But any four-state type can be used.
    uwire [7:0] i_am_logic;
    uwire logic [7:0] i_am_logic_too;
    uwire integer i_am_an_integer_which_is_a_thirty_two_element_array_of_logic;

// Some net kinds:
//
//  :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;   // Can have multiple drivers. Avoid this if you can.
   uwire wire_2;  // Can have at most one driver. Otherwise a compile error.
   logic r1;      // Defaults to var kind, not a net kind.

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

   and a1(wire_2,a,b);

   // This declaration is a continuous assignment, NOT an initialization.
   uwire 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 @* begin
      r1 = a;

      // wire_4 = b; // Not allowed because wire_4 is a net kind.

   end

endmodule




//////////////////////////////////////////////////////////////////////////////
/// Array Ranges
///

 ///   :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.
//     These are called unpacked arrays in the material above.
//     Synthesizable.
//
//      :Example: int a[4];
//       Valid indices: 0, 1, 2, 3
//
//      :Example: int a[S];   // Synthesizable if S is constant.
//       Valid indices are: 0, 1, ..., S - 1
//
//
 ///     Static Arrays: Range.
//     These too are called unpacked arrays in the material above.
//     Synthesizable.
//
//      :Syntax: ELEMENT_TYPE IDENT[LAST:FIRST];
//       Element indices are FIRST, FIRST+1, ..., LAST  if LAST > FIRST
//       Element indices are FIRST, FIRST-1, ..., LAST  if LAST < FIRST

`ifdef xxx
//
         int a[10:8];
//       Valid indices: 10, 9, 8.
//       In other words, a[9] is okay, but a[7] is out of range.
//
         int a[8:10];
//       Valid indices: 10, 9, 8.
//
         real I_love_FORTRAN[5:1];
//       Valid indices: 5, 4, 3, 2, 1

         real C_rules_rule[4:0];
//       Valid indices: 4, 3, 2, 1, 0

         real because_I_can[1:-3];
//       Valid indices: 1, 0, -1, -2, -3
`endif
//
 ///     Zero v. One for First Index
//     https://xkcd.com/163/





//////////////////////////////////////////////////////////////////////////////
/// Array Variations: Static, Dynamic, Associative
///

 /// Array Variations: Static, Dynamic, Associative
//
//   The arrays covered so far are static arrays.
//   Dynamic and associative arrays are used in testbenches.

 ///     Dynamic Arrays
//
//     :Def: Dynamic Array
//          An array whose size can change.
//          Usually declared without a size.
//
//     Not realistically 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
//
//      :Def: Associative Array
//       An array that is indexed by a value that does not indicate
//       the element's exact position in the array.
//
//       Associative arrays often used in scripting languages like
//       Perl and Python.
//
//
//     Not realistically 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 array_examples
  #( int num_elts2 = 6 )
   (input int num_elts);

   logic [7:0] array1b[4:10];
   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 array3b[integer];
   int array4[10:1];            // Ten elements, indices 1..10

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

   initial begin

      #0; // Wait for num_elts to be set.

      $write("Array examples num_elts = %0d\n",num_elts);

      array1 = new [ num_elts ];

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

      array2[ "5" ] = 1;
      array2[ "five" ] = 2;
      array2[ "six" ] = 3;
      array2[ "five" ] = 5;
      // At this point array2 has 3 elements.
      array2.delete("5");
      // At this point array2 has 2 elements.

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

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

      begin
         int x1, x2;
         x1 = array1[5];
         x2 = array2["five"];
      end

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

   end

endmodule

module array_examples_test;

   array_examples ae(6);

endmodule


 /// Dynamic Arrays
//
//   :SV12: 7.5
//
//   :Keyword: new[NUM_ELTS](init)  --
//   :Keyword: size() -- Member function, return number of elements.
//      :Example: int s = a.size();
//   :Keyword: delete() -- Member function, delete all elements.

 /// 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).
//
//   :Sample: foreach ( a[i] ) b[i] = a[i];




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



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