/// Notes  and Demos for LSU EE 4702-1 Spring 2001

//  Gate and Net Delays

//  Sources: Ci:  Ciletti, Modeling, synthesis, and rapid prototyping
//                         with the Verilog HDL
//           LRM: IEEE,    Verilog Language Reference Manual

/// Contents

// Gate Delay
// Wire Delay 
// Module Delay


/// Gate Delay

//  Ci 6.3  LRM 7.15

//  GATE #DELAY NAME(TERMINALS)
//  GATE #(TO_1_DELAY,TO_0_DELAY) NAME(TERMINALS)
//  GATE #(TO_1_DELAY,TO_0_DELAY,TO_Z_DELAY) NAME(TERMINALS)

//  DELAY, TO_1_DELAY, TO_0_DELAY, and TO_Z_DELAY  can be
//    SINGLEDELAY
//    MIN:TYPICAL:MAX
//    where SINGLEDELAY, MIN, TYPICAL, and MAX are constant expressions.

//  DELAY specifies the time from a change in any input to
//   a change in an output.

//  Default delay is zero.

 /// Demonstration of single delay. 
module gde_1();  // Gate Delay Examples

   reg a, b;
   wire x;

   // Specify a ten-cycle delay for *gate* and.
   and #(10) and1(x,a,b);

   // Specify a value of 10 for first parameter (covered later) to
   // *module* bfa_structural.  This is not a delay because
   // bfa_structural is a module, not a gate.
   bfa_structural #(10) bfa1(sum,cout,a,b,c);

   initial begin

      a = 1; b = 0;

      #20;

      // Output goes to 1 ten cycles later.
      b = 1;  

      #20;

      // Output goes to 0 ten cycles later.
      b = 0; 

      #20;

      // Output goes to x ten cycles later.
      b = 1'bx;

      #20;

      // Output goes to 1 ten cycles later.
      b = 1;

      #20;

      // Output would go to 0 ten cycles later...
      b = 0;

      #5;

      // ... but this "cancels" the transition to 0.
      b = 1;

      #20;

   end

endmodule

 /// Demonstration rising and falling delay. 
module gde_2();  // Gate Delay Examples

   reg a, b;
   wire x;

   // Specify a 5-cycle to-1 (rising) delay and a 10-cycle to-0 (falling) delay.
   // The to-x and to-z delays are min {5,10} = 5.
   and #(5,10) and1(x,a,b);

   initial begin

      a = 1; b = 0;

      #20;

      // Output goes to 1 five cycles later.
      b = 1;  

      #20;

      // Output goes to 1 ten cycles later.
      b = 0; 

      #20;

      // Output goes to x five cycles later.
      b = 1'bx;

      #20;

      // Output goes to 1 five cycles later.
      b = 1;

      #20;

      // Output would go to 0 ten cycles later...
      b = 0;

      #7;

      // ... but this "cancels" the transition to 0.
      b = 1;

      #20;

      b = 0;

      #20;

      b = 1;

      #7;

      b = 0;

      #20;

   end

endmodule

 /// Demonstration rising,  falling, and to Z delay. 
module gde_3();  // Gate Delay Examples

   reg c; // Control
   reg d; // Data.
   wire x;

   // Specify a 5-cycle to-1 (rising) delay, a 10-cycle to-0 (falling)
   // delay, and a 15-cycle to-Z delay.  The to-x delay is
   // min {5,10,15} = 5.
   bufif1 #(5,10,15) tri_state_buffer_1(x,d,c);

   initial begin

      c = 1; d = 0;

      #20;

      // Output goes to 1 five cycles later.
      d = 1;  

      #20;

      // Output goes to 1 ten cycles later.
      d = 0; 

      #20;

      // Output goes to x five cycles later.
      d = 1'bx;

      #20;

      // Output goes to 1 five cycles later.
      d = 1;

      #20;

      // Output would go to 0 ten cycles later...
      d = 0;

      #7;

      // ... but this "cancels" the transition to 0.
      d = 1;

      #20;

      // Output goes to z in fifteen cycles.
      c = 0;

      #20;

   end

endmodule


/// Wire Delay

//  Ci 6.5  LRM 6.1

//  NET_TYPE DELAY3 NETNAMES;

module delay_module(x,a);
   output x;
   input a;

   wire #5 a;  // This delay isn't counted by modelsim.
   wire #7 x = a;

endmodule

module wde();  // wire_delay_examples

   reg     start;
   wire    dmout;

   delay_module dm(dmout,start);
   
   wire #3 start_3 = start;
   wire    first_out_0;
   wire #9 first_out_9;
   and #6  and1(first_out_9,start_3,start_3);
   and #6  and2(first_out_0,start_3,start_3);
   wire    second_out_0;
   wire #4 second_out_4;
   or #12  or1(second_out_4,first_out_9,first_out_9);
   or #12  or2(second_out_0,first_out_9,first_out_9);

   initial begin
      start = 1;
      wait( second_out_4 );
      #2;
   end

endmodule


/// Specifying Module Timing

// Ci 6.6  LRM 13.4

// Timing for a module can be specified explicitly. (As opposed
// to setting delays for gates, wires, and behavioral code.

// Timing specified for *paths* from input to output in a specify
// block.  
// The specify block description below is for one of several
// forms, the others won't be covered.
// The specify block is placed anywhere within a module.

// specify
//   ( INPUTS1 *> OUTPUTS1 ) = DELAY1;
//   ( INPUTS2 *> OUTPUTS2 ) = DELAY2;
//   ..
// endspecify

//  INPUTS1 is an individual or comma-separated list of module inputs
//  OUTPUTS1 is an individual or comma-separated list of module outputs
//  DELAY1 is a delay specification which can be in the form used
//  for gate delays.


// In the example below a delay is specified for the behavioral
// pop module, perhaps to make its timing realistic.

module test_pop_delay();
   reg [7:0]  a;
   wire [3:0] pop;
   
   pop_behavioral_8 pop1(pop,a);

   initial begin
      a = 8'b0;
      #3;
      a = 8'h3;
      #10;
      a = 8'hff;
      #10;
   end
   
endmodule

module pop_behavioral_8(pop,a);
   input a;
   output pop;

   specify
      ( a *> pop ) = 5;
   endspecify
   
   wire [7:0] a;
   reg [3:0]  pop;
   integer    a_work, pop_work;

   // Executes whenever a changes.
   always @( a ) begin

      pop_work = 0;
      a_work   = a;

      while( a_work ) 
        begin
           pop_work = pop_work + a_work[0];
           a_work   = a_work >> 1;
        end

      // Note: pop changes once per change in a.
      pop = pop_work;

   end

endmodule

module demo_adder();

   reg [7:0] a, b;
   wire [7:0] sum;
   
   adder_8 adder1(sum,a,b);

   initial begin
      a = 0;  b = 0;
      #5;
      a = 100;  b = 50;
      #20;
      a = 77;  b = 33;
      #20;
   end

endmodule

module adder_8(sum,a,b);
   input a, b;
   output sum;

   wire [7:0] a, b, sum;

   wire [7:0] cry;

// (loop for i from 0 to 7 do (insert
//        (format "\nbfa_implicit bfa%d(sum[%d],cry[%d],a[%d],b[%d],cry[%d]);"
//                i i i i i (- i 1))))

   bfa_implicit bfa0(sum[0],cry[0],a[0],b[0],1'b0);
   bfa_implicit bfa1(sum[1],cry[1],a[1],b[1],cry[0]);
   bfa_implicit bfa2(sum[2],cry[2],a[2],b[2],cry[1]);
   bfa_implicit bfa3(sum[3],cry[3],a[3],b[3],cry[2]);
   bfa_implicit bfa4(sum[4],cry[4],a[4],b[4],cry[3]);
   bfa_implicit bfa5(sum[5],cry[5],a[5],b[5],cry[4]);
   bfa_implicit bfa6(sum[6],cry[6],a[6],b[6],cry[5]);
   bfa_implicit bfa7(sum[7],cry[7],a[7],b[7],cry[6]);

endmodule

module bfa_implicit(sum,cout,a,b,c);
   input a,b,c;
   output sum,cout;

   assign #3 sum = 
          ~a & ~b &  c |
          ~a &  b & ~c |
           a & ~b & ~c |
           a &  b &  c;

   assign #2 cout = a & b | b & c | a & c;

endmodule