///  LSU EE 4755 -- Fall 2016 -- Digital Design / HDL
///
///  Rudiments of Behavioral Code

/// Contents

 // Behavior Code and Structured Procedures
 // The initial Structured Procedure
 // Basics of Delay (#) and Event (@) Controls
 // The always Structured Procedure
 // The $display system task, and a testbench example.


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


////////////////////////////////////////////////////////////////////////////////
/// Behavioral Code

//  Behavioral code is used to specify what hardware does rather than
//  describe it as an interconnection of simpler components (as does
//  structural code). Behavioral code looks like a program in a
//  conventional programming language but there are major differences,
//  one difference is in when code starts running. In C execution
//  starts with the "main" routine, procedures are executed when they
//  are called. In Verilog behavioral code is invoked in a variety of
//  ways, some times in a way similar to a procedure call, other times
//  in response to a change in a signal.

//  Details on behavioral code will be presented later, the rudiments
//  are presented here so that behavioral code can be used Verilog
//  examples.

// :SV09: Section 9.2
// :BV3: Section A.11.1


 /// Specifying Behavioral Code
//
//  Behavioral code is placed in a /structured procedure/.
//  When and how many times the behavioral code executes depends
//    on the particular structured procedure.

 /// Structured Procedures
//
// :Keyword: initial STATEMENT
//           Start statement at t=0.
//
// :Keyword: always STATEMENT
//           Execute statement repeatedly, statement MUST have
//             a timing or event control (unless your goal is to
//             hang the simulator).
//
// :Keyword: always_comb STATEMENT
//           Execute statement at t=0 and whenever live-in objects change.
//           Use this when STATEMENT describes combinational logic.
//
//           There are two additional always_FOO statements, they
//              will be covered later.
//
// :Keyword: final STATEMENT
//           Execute statement before simulator exits.
//
// STATEMENT is usually a block, e.g.,  begin a=1; etc.... ; end



////////////////////////////////////////////////////////////////////////////////
/// Initial Blocks

// :SV09: Section 9.2.1
// :BV3: Section A.11.1

 /// Placement
//
//   Appear in modules and programs (programs not yet covered).
//   Can have any number.

 /// Execution Timing
//
//   All initial blocks start at t=0.
//

 /// Typical Uses
//
//   Initialization.
//
//   Testbench.


 /// NOT USED FOR
//
//   Describing synthesizable hardware.


// :Example:
//
//  Simple example.

module mymod1(input myport, output alsomyport);
   logic  a, b;

   // Starts running at t=0.
   initial begin
      a = 1;
      b = myport;
   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Delays and Event Controls

// :SV09: Section 9.4 up to and including 9.4.2.1

 /// Description
//
// Delay and event controls are used to pause the execution of
// behavioral code. With a delay, execution of the piece of behavior
// code is paused for a given amount of time. With an event control,
// execution is paused until something happens. The pause only affects
// the behavioral code in which the delay or event control
// appears. During the pause the simulator will do something else.

// Here only a basic description is given. Later, more advanced
// treatment will be given, including non-blocking delays and
// the simulator event queue.


 ///              Delay Control
//
// :Keyword: # AMT STATEMENT
//           Wait AMT time units, then execute STATEMENT.

 ///              Event Control
//
// :Keyword: @* STATEMENT
//           Wait until any source object in STATEMENT changes.
//           The "*" is called an implicit event expression list.

// :Keyword: @ ( A or B or ... ) STATEMENT
//           Wait for A or B to change, then execute statement.
//           Sensitivity List: the "A or B or ..." part.
//


// :Example:
//
// Simple delay and event control examples.
//
module delay_and_event_demo(input b);

   int a;

   initial begin

      a = 1;      // Assignment occurs at t = 0;

      // Below, a changes at t = 5.
      //
      #5 a = 2;  // AMT -> 5,  STATEMENT -> "a = 2;"

      // At this point t = 5;

      #7;  // AMT -> 7,  STATEMENT -> ";" (Statement is empty.)

      // a is assigned at t = 12.

      a = 3;

      @ ( b );  // Wait until b changes.

      // Assume that b next changes at t=20.

      a = 4;   // a assigned at t = 20.

      // Wait until b changes. (b is used as a source in STATEMENT.)
      //
      @*  a = b;  // STATEMENT -> "a = b;"


   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Always Blocks

// :SV09: Section 9.2.2
// :BV3: Section A.11.1

 /// Description
//
 // :Keyword: always STATEMENT
//
//   - STATEMENT starts at t=0;
//   - The amount of time STATEMENT takes depends on its contents.
//     Assume that STATEMENT always takes 5 units.
//     - Then STATEMENT will finish at t=5 ...
//     - ... and then will start again at t=5 (hence always) ...
//     - ... and will finish at t=10 ...
//     - ... and start again at t=10 ...
//
//  Note: There will be an infinite loop (deadlock) if STATEMENT
//  does not contain some kind of delay or event control.
//
 // :Keyword: always_comb STATEMENT
//
//  Restriction: STATEMENT cannot have timing (e.g, #3;) 
//               nor event controls (@(a or b);).
//
//   - STATEMENT executes at t=0.
//   - STATEMENT executes whenever an object used in STATEMENT changes.

 /// Common Use of Always -- Describe Combinational Logic
//
//   :Sample: always @* STATEMENT
//   :Sample: always_comb STATEMENT



// :Example:
//
// Use of always to generate a clock signal.

module myclockgen(output logic clock);

   initial clock = 0;

   always #5 clock = !clock;

endmodule


// :Example:
//
// Good use of always, once upon a time.
// Now it's bad!
//
module mymod2good(output logic x,y,z, input a,b,c);

   // Runs each time a or b or c changes.
   //
   always @( a or b or c ) begin
      x = a + 1;
      y = b + c;
   end
endmodule

// :Example:
//
// Unusual use of always. Probably an error.
//
module mymod2bad(output logic x,y,z, input a,b,c);

   // Runs each time a or b changes. Won't run if only c changes.
   //
   always @( a or b ) begin
      x = a + 1;
      y = b + c;
   end

endmodule


// :Example:
//
// Use of implicit event expression. always_comb
//
module mymod21(x,y,z,a,b,c);
   input  a, b, c;
   output x, y, z;
   logic    x, y, z;

   // Runs at t=0 and each time any right-hand-side object changes.
   //
   always_comb begin
      x = a + 1;
      y = b + c;
   end

endmodule


/// Multiple initial And always Blocks

// A module can have any number of initial and always constructs.
// Timing and other details will be discussed later.

module mymod3(output logic x,y,z, input a,b,c);

   // Runs at initialization.
   initial begin
      x = 1;
   end

   // Runs at initialization ..
   // .. either before or after the block above.
   initial begin
      y = 1;
   end

   // Runs each time x changes.
   //
   always @( * ) begin
      y = 2 + x;
   end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Simple Testbench, and the $Display System Task

// :SV09: Section 21.2


// The following are useful in procedures.  They are covered briefly
// below and will be covered in detail later.

// :Keyword: $display
// :Keyword: $write
//
// The $display system task.
//  Used in procedures to print messages in the transcript.
//  Similar to the C printf library function.

//  :Syntax: $display(FORMAT,ARG1,ARG2,...)
//  FORMAT is a string that can contain escape sequences.
//  ARG1, ARG2 are the values to be printed.
//  Format escape sequences start with a % and followed by a format character.
//   Format characters: %d (decimal), %h (hex), %o (octal), %b (binary)
//                      %c (character), %s(string), %t(time), ...
//
//  Examples:

//  $display("The values are: i=%0d or %h (hex) time=%t\n", i, i, $time);

// This is one of many system tasks.


// :Example:
//
// Use of behavioral code to write a testbench for a simple "imply"
// module.  The testbench is in module demo_the_tedious_way.

module imply(x,a,b);
   input a, b;
   output x;
   wire   x = ~a | b;
endmodule // imply

module demo_the_tedious_way();

   logic a, b;
   wire x;

   imply imp1(x, a, b);

   initial begin

      // Here t = 0 (units discussed later).

      a = 0;  b = 0;

      $display("At the very beginning, t=%t, x= %d\n",$time,x);

      // This delays execution for one unit.
      #1;

      $display("A little later, t=%d,  x= %d\n",$time,x);

      #1;

      a = 0;  b = 1;

      $display(" t = %t, x = %d\n",$time,x);

      #1;

      $display(" t = %t, x = %t\n",$time,x);

      #1;

      a = 1;  b = 0;

      #1;

      $display(" t = %t, x = %d\n",$time,x);

      #1;

      a = 1;  b = 1;

      #1;

      $display(" t = %t, x = %d\n",$time,x);

      $stop;

   end

endmodule


// :Example:
//
// Same testbench as code above, but using a for loop to simplify
// things.

module demo_the_better_way();

   int i;
   wire    a = i[0];
   wire    b = i[1];
   wire    x;

   imply imp1(x, a, b);

   initial begin

      for ( i=0; i<4; i++ ) begin

         $display("At the beginning of an iteration. t=%t, x=%d.\n", $time,x);
         #1;
         $display("In the middle of an iteration. t=%t, x=%d.\n", $time,x);
         #1;
      end

      $stop;

   end

endmodule