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

//  Miscellaneous

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


/// Contents
//
// Miscellaneous
// Include
// Defines define
// Removing Definitions (undef)
// Testing Definitions (ifdef,else,endif)
// Hierarchical Path Names
// Parameters
// Defparam
// Named Ports
// Procedural Continuous Assignments 
// Other compiler directives.        (Coming soon.)



/// Include

// LRM 16.5

// `include "PATHNAME"
//
// PATHNAME: A valid file or pathname.
//
// Insert contents of PATHNAME at current location. 

`include "utility.v"

// Not a good use of include.  Good uses further below.
module x();

   handy h1(a,b,y);

endmodule


/// Defines

//  LRM 16.3

// Below: define

 /// Macro definition:  `define NAME MACRO_TEXT
//
// NAME: An identifier
// MACRO_TEXT: Almost any text.  Text ends at next line not ending with '\'
//  Cannot start or end in the middle of a comment, operator, keyword,
//  string, numbers, or identifier.
//
// Substitute occurrences of `NAME (note back tic) with MACRO_TEXT

// Replace occurrences of FOO with BAR.
`define FOO BAR
// One way of defining a constant.
`define BUS_WIDTH 16
// A five-line macro.
`define LOTS_OF_STUFF a = 1; \
   b = 2;                                                                       \
   c = 3;                                                                       \
   $display("Thank you for using the LOTS_OF_STUFF macro.");                    \
   $display("Have a nice day.");


`define EXP a + b
module mac_ex();

   integer bus_w;
   integer x, a, b, d;
   
   initial begin

      bus_w = `BUS_WIDTH;

      x = `EXP + d;

   end

endmodule

 /// Macro Definition:  `define NAME(FORMAL_ARGS) MACRO_TEXT
//
// NAME: An identifier
// FORMAL_ARGS: FORMAL_ARG1, FORMAL_ARG2, ...
//  Each FORMAL_ARGn is an identifier.
//
// Macro Use


// Compute the minimum.  Note parenthesis.
`define MIN(a,b) ((a)<(b)?(a):(b))
// Useful in for loops. (See example below.)
`define PP(a) a=a+1

 /// WARNING:  parenthesis around a omitted.  Don't let it happen to you!
`define DOUBLE(a) 2*a

// Not satisfied with current keywords?

`define unless(cond) if(!(cond))
`define until(cond) while(!cond)

`define infinite_recur `infinite_recur

`define CHECK(var)                                                              \
if( ^var === 1'bx ) $display("Value undefined");                               \
 else if( var < 0 ) $display("Too low.");                                       \
   else if( var > 100 ) $display("Too high.");

module define_examples();

   integer foo, bar, i, j;

   initial begin

      // The modelsim compiler will hang on the line below.
      // `infinite_recur

      // Why parenthesis should be put around macro arguments.
      $display("Double of 2 is %d, double of 1+1 is %d",
               `DOUBLE(2), `DOUBLE(1+1));

      j = 0;

      for(i=0; i<10; `PP(i))
        begin
           `unless( i < 9 ) $display("i is %d",i);
           j = j + i;
        end

      bar = 2;
      foo = `MIN(3,bar);
      
   end
   
   
`ifdef DEBUG
   always @( foo )
      if( foo != bar ) begin
         $display("It happened!");
         $stop;
      end
`endif
   

endmodule

/// Removing Definitions

// LRM 16.3

// `undef NAME
//
// NAME: An identifier.
//
// Remove definition of NAME, if any.

`define BREAKFAST eggs
// On second thought...
`undef BREAKFAST
`define BREAKFAST cereal

 /// An example of poor style that will make debugging difficult.

`define TEMPMAC  ((a)+(b)/(c))

// Lots of code, some using TEMPMAC

`undef TEMPMAC
`define TEMPMAC (2*(x)+(y))


 /// A better use of `undef.

// Use with include to make custom alus.

`define WIDTH 64
`define ALUNAME alu_addsub
`define OP0(r,a,b) r=a+b;
`define OP1(r,a,b) r=a-b;
`include "generic_alu.v"

`undef ALUNAME
`undef OP0
`undef OP1
`define ALUNAME alu_andor
`define OP0(r,a,b) r=a&b;
`define OP1(r,a,b) r=a|b;
`include "generic_alu.v"

`undef WIDTH 
`define WIDTH 32
`undef ALUNAME 
`undef OP0
`undef OP1
`define ALUNAME alu_minmax
`define OP0(r,a,b) if( a < b ) r = a; else r = b;
`define OP1(r,a,b) if( a > b ) r = a; else r = b;
`include "generic_alu.v"



 /// Another good use of `undef.

// The bean counter testbench description is being used to test 3 different
// modules.

`define BEANMOD beancount
`define BEANTESTMOD beantest
`include "beantest.v"

`undef BEANMOD
`define BEANMOD beancount_s
`undef BEANTESTMOD 
`define BEANTESTMOD beantest_s
`include "beantest.v"

`undef BEANMOD
`define BEANMOD beancount_x
`undef BEANTESTMOD 
`define BEANTESTMOD beantest_x
`include "beantest.v"


/// Testing Definitions

// LRM 16.4

// `ifdef NAME
// `else
// `endif

`define METHOD1

module mymod(somevar);
   input somevar;

`ifdef METHOD1
 // some stuff
   initial begin
      // METHOD1 code.
   end

   always @( somevar )
     begin
        
     end
`else
   initial begin
      // METHOD2 code
   end
   
   
`endif

endmodule

/// Hierarchical Path Names

// LRM 12.4

// Hierarchical path name is full name of an identifier.

module top_mod();

   lower_mod lm();

   initial $display("avar is %d",lm.avar);

   initial lm.avar = 3;

endmodule

module lower_mod();

   reg avar;

   initial avar = 1;

endmodule

module another_top_mod();

   initial $display("avar is %d", top_mod.lm.avar);

endmodule



module hpn_one();

   hpn_two h2a();
   hpn_two h2b();

   initial $display("States %d %d",
                    h2a.louisiana,
                    h2b.louisiana);

   initial $display("Fruits: ",
                    h2a.h3a.apple,
                    h2a.h3b.apple,
                    h2b.h3a.apple,
                    h2b.h3b.apple);

   
   initial $display("Consumer Electronics: ",
                    h2a.h3a.IBLOCK.tv,
                    h2a.h3b.IBLOCK.tv,
                    h2b.h3a.IBLOCK.tv,
                    h2b.h3b.IBLOCK.tv);

   initial $display("Pets: ",
                    h2a.h3a.IBLOCK.ABLOCK.cat,
                    h2a.h3b.IBLOCK.ABLOCK.cat,
                    h2b.h3a.IBLOCK.ABLOCK.cat,
                    h2b.h3b.IBLOCK.ABLOCK.cat);

endmodule

module hpn_two();

   reg louisiana, texas;

   hpn_three h3a();
   hpn_three h3b();

endmodule

module hpn_three();

   reg apple;
   wire banana;

   initial begin:IBLOCK

      reg tv;
      reg radio;

      begin:ABLOCK

         reg cat;
         reg dog;

         cat = 111;
         dog = 222;

         $display("cat %d, dog %d",cat,dog);

      end

      begin:BBLOCK

         $display("cat %d, dog %d",IBLOCK.ABLOCK.cat,IBLOCK.ABLOCK.dog);

      end
      

   end


endmodule



/// Parameters

// LRM 12.2

// Constants for use in a module.
// Module specifies default which can be overridden in instantiation. 

 /// Parameter Declaration
//
// module FOO(bar);
// parameter PARNAME1 = DEFAULT_PAR_VAL1;
// parameter PARNAME2 = DEFAULT_PAR_VAL2;
// ...
//
// PARNAME: An identifier.
// DEFAULT_PAR_VAL: An expression that evaluates to a constant at compile time.
//
// Specify default values for parameters.
// E.g., DEFAULT_PAR_VAL1 is the default for PARNAME1.

 /// Specifying Parameter Values in Instantiations
//
// FOO #(PAR_VAL1,PAR_VAL2,..) MYFOO(MYBAR);
//
// Specify values used in an instantiation.
// E.g., PAR_VAL1 used for parameter 1 (overriding DEFAULT_PAR_VAL1).

 /// Specifying Parameter Values in Modules
//
// defparam HIERARCHICAL_PATH_PARAMNAME = VAL;
//
// Set PARAMNAME in HIERARCHICAL_PATH to VAL



module param_examples();

   // This is a constant, but be careful when using floating-point numbers.
   parameter pi = 3.1415926535897932384626433832795028841971693993751058209;

   // This is okay since compiler can compute expression.
   parameter seconds_in_a_non_leap_year = 60 * 60 * 24 * 365;
   // This is okay since compiler can compute expression because pi
   // is a constant.
   parameter twopi = 2 * pi;

   integer   i;
   initial begin

      // Correct use of a parameter.
      i = seconds_in_a_non_leap_year / 12;

      // Line below won't work, can't modify a parameter.
      // pi = 3;

      

   end
   

   reg       w,v;

   initial begin w=1; v=2; end

   // Won't work: w and v are not known at compile time.  It doesn't
   // matter that they are set at start of simulation and don't change.
   // parameter wplusv = w + v;

endmodule

 /// Using parameters as constants in an ALU module.

// Though sub works, the name is not needed throughout this file,
// so it should be declared within the module as a parameter.
`define sub 1

// Sum works.  A parameter could not be used since a+b is not
// a constant expression.
`define sum a+b

module alu_p(result,op,a,b);
   input op, a, b;
   output result;

   parameter add    = 0;
//   parameter sub    = 1;
   parameter pass_a = 2;
   parameter pass_b = 3;
   parameter and_op = 4;
   parameter or_op  = 5;

   // Cannot use a parameter since a-b is not a compile-time constant.
   //  parameter diff = a - b;

   reg [63:0] result;
   wire [63:0] a, b;
   wire [2:0]  op;

   always @( op or a or b )
     case( op )
       add     : result = `sum;
       `sub     : result = a - b;
       //`sub     : result = diff;
       pass_a  : result = a;
       pass_b  : result = b;
       and_op  : result = a & b;
       or_op   : result = a | b;
       default : result = 0;
     endcase

endmodule


 /// Using parameters for the width and delay for a multiplexor.

module mux_16_4(out,in0,in1,in2,in3,c);
   input in0, in1, in2, in3, c;
   output out;

   parameter width = 16;
   parameter del = 3;

   reg [width-1:0] out;
   wire [width-1:0] in0, in1, in2, in3;
   wire [1:0]  c;

   always @( in0 or in1 or in2 or in3 or c )
     # del case( c )
       0: out = in0;
       1: out = in1;
       2: out = in2;
       3: out = in3;
     endcase
   
endmodule

module use_mux();

   reg [1:0] c;
   reg [7:0] in0_a, in1_a, in2_a, in3_a;
   reg [15:0] in0_b, in1_b, in2_b, in3_b;
   wire [7:0] out_a;
   wire [15:0] out_b;

   mux_16_4 #(8) mux_a(out_a,in0_a,in1_a,in2_a,in3_a,c);
   mux_16_4 #(16,7) mux_b(out_b,in0_b,in1_b,in2_b,in3_b,c);
   mux_16_4 mux_c(out_b,in0_b,in1_b,in2_b,in3_b,c);
   and #(8) a1(x,a,b);

   /// Note: The syntax for specifying module parameters and gate delays
   // are similar, but the semantics (meaning) of a module
   // parameter is very different than a gate delay.

endmodule


// Similar to use_mux, but use defparam to specify parameter values.
module use_mux2();

   reg [1:0] c;
   reg [7:0] in0_a, in1_a, in2_a, in3_a;
   reg [15:0] in0_b, in1_b, in2_b, in3_b;
   wire [7:0] out_a;
   wire [15:0] out_b;
   
   mux_16_4 mux_a(out_a,in0_a,in1_a,in2_a,in3_a,c);
   mux_16_4 mux_b(out_b,in0_b,in1_b,in2_b,in3_b,c);
   mux_16_4 mux_c(out_b,in0_b,in1_b,in2_b,in3_b,c);
   and #(8) a1(x,a,b);

endmodule

module set_mux2();

   defparam use_mux2.mux_a.width = 8;
   defparam use_mux2.mux_b.width = 16;

endmodule



/// Named Ports


module norad_vending_machine(coffee,hot_chocolate,thermonuclear_war,tea);
   input coffee,hot_chocolate,tea,thermonuclear_war;

   // Code removed for security purposes.

endmodule

module np_example();

   reg joe,hc,tea,war;

   // Ooops.
   norad_vending_machine mynvm(joe,hc,tea,war);

   // No problem here: Simulator or other software that
   // resolves instantiations will detect the port order problem,
   // saving the world.
   norad_vending_machine mynvm1(.coffee(joe),
                                .hot_chocolate(hc),
                                .tea(tea),
                                .thermonuclear_war(war));

endmodule

/// Procedural Continuous Assignments

//  LRM 9.3

// assign REG_ASSIGNMENT
// deassign REG_NAME
//
// Used in procedural code.
//
// assign: Specify that continuous assignment is to start to a reg.
// deassign: End a continuous assignment.

// force REG_OR_NET_ASSIGNMENT
// release RET_OR_NET_NAME
//
// Used in procedural code.
//
// force: Specify that continuous assignment to start to a register or net type.
// release: End a continuous assignment.

// Characteristics
//
// While a continuous assignment is active ordinary assignment has no effect.
// A second continuous assignment replaces the old one.

 /// These should only be used for special purposes, such as debugging.




module pca_example();
   integer a, x;

   wire    [31:0] w, w1;

   assign  w1 = x + 1;
   assign  w = x + 1;

   initial begin
      a = 10;
      x = 1;
      // Set up a continuous assignment to a.  Now a will be x + 1.
      assign a = x + 1;
      force w1 = x + 1;
      $display("1 a is %d",a);
      x = 2;
      $display("2 a is %d",a);
      #0;
      $display("2 after 0 a is %d",a);
      // The assignment below has no effect.
      a = 20;
      #0;
      $display("20 a is %d",a);
      deassign a;
      $display("de a is %d",a);
      a = 30;
      $display("30 a is %d",a);
      release w1;
   end
   

endmodule


/// Other Compiler Directives

// Coming soon.