```///  LSU EE 4755 -- Fall 2017 -- Digital Design / HDL
///
///  Verilog Review

/// Contents

// Review of Module Instantiation
// Verilog Simulation Basics
// Description of descriptive styles.

/// References

// :SV12: IEEE 1800-2012 -- The SystemVerilog Standard
//        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.
//        This is for those who need to review basic Verilog.

////////////////////////////////////////////////////////////////////////////////
/// Modules and Module Instantiation

// :BV2:, :BV3: 2.10 --  Good description.
// :SV12: 23 Complete details. (Note: ANSI style used in class.)

/// A module describes a part,
//    can be simpler than a gate
//    or more complex than an entire computer.
//
//  A module is defined once (see example) and can be /instantiated/,
//  used, within other modules or recursively.  Examples of instantiation
//  provided further below.

// :Example:
//
// Definition of a module for the illustrated circuit.
//
//
//
module pie
( output uwire x, y,
input uwire a, b, c );

uwire t1, t2;

xor x1(t1,a,b);   // Instantiation of primitive xor.
not n1(x,t1);
and a1(t2,x,c);
or  o1(y,t2,b);

endmodule
//
// The module above instantiates four primitive gates (the xor, not,
// and or). In the next example a module will be defined in terms of
// other modules.

// :Example:
//
// Definition of a module which uses the module above.
// The two_pie module, below, itself instantiates
//
module two_pie
( output uwire o1, o2,
input uwire f, g, h, a );

uwire   i1, i2;

pie apple (i1, i2,  f,  g,  h );        // Instantiation of module pie.
pie cherry(o1, o2,  i1, i2, a );

endmodule
//
// Illustration of the module above:
//

//////////////////////////////////////////////////////////////////////////////
/// Verilog Simulation Basics
//
//  :SV12: Section 4.3.  Complete details, not the basics.
//
//   Simulation is the "running" of a Verilog description.
//
//   Structural code executes in reaction to changes in signal values.
//
//   Here's a simplified description:
//
//     An event queue (todo list of sorts) contains update events,
//       which are signals that have changed or will change.
//
//     An update event (signal) from the queue is dequeued (removed),
//       or if the queue is empty we're done.
//     Suppose signal f from two_pie is dequeued.
//
//     The simulator will find the primitive gates and behavioral
//       constructs (assign, always, etc) that the signal connects
//       to.
//     In the example above, f connects to primitive gate x1 in apple.
//
//     The simulator will evaluate code associated with the primitive
//       or behavioral construct. As a result of this evaluation new
//       update events (signal changes) may be generated and placed in
//       the event queue.

//     In the example above, t1 in apple changes value.
//
//     Go to the first step.

// :Example:
//
// Possible order of execution for two_pie given a change in f:

// Dequeued     Evaluated Item      New Update Events
// --------     --------------      -----------------
// f = apple.a
//              -> xor apple.x1,    changing apple.t1
//
// apple.t1
//              -> not apple.n1,    changing apple.x.
//
// apple.x = i1 = cherry.a
//              -> and apple.a1,    changing apple.t2
//              -> xor cherry.x1,   changing cherry.t1
// Note: two values have changed.
//
// apple.t2
//               -> or apple.o1,    changing apple.y
//
// cherry.t1
//               -> not cherry n1,  changing cherry.x
//
// Subsequent execution not shown.

/// Notes:
//
//   It's easy to create infinite loops.
//
//   It is possible to add timing controls to affect the ordering.
//
///  The execution order above is not affected by instantiation order.
//      For example swapping the position of apple and cherry would
//      have no affect.

module pie_two
( output uwire o1, o2,
input uwire f, g, h, a );

uwire   i1, i2;
// Note: This is equivalent to two_pie.
pie cherry(o1, o2,  i1, i2, a );
pie apple (i1, i2,  f,  g,  h );        // Instantiation of module pie.

endmodule

////////////////////////////////////////////////////////////////////////////////
/// Primitives
//
// :SV12: Section 28.4, and nearby sections.
//
/// Primitives are the building blocks for structural code.
//
// They are instantiated like modules, but they are not themselves
// defined.
//
// There are primitives for common logic gates, and for devices
// such as tri-state buffers and transmission gates.
//
/// In most cases primitives should not be used because other
/// code forms are much less tedious.
//
//
// That said, the logic primitives are:
//  :Keywords: and,nand,or,nor,xor,xnor,buf,not

/// Connections to Logic Primitives.
//
//   The first output of every logic primitive is its output.
//   In most cases there can be any number of inputs.

// :Example:
//
// Example illustrating different number of inputs.
//
module prim_examples;

uwire my_output, my_other_output;
uwire i0, i1, i2, i3, i4, i5, i6, i7, i8, i9,
i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23,
i24, i25, i26, i27, i28, i29, i30, i31, i32, i33, i34, i35, i36, i37,
i38, i39, i40, i41, i42, i43, i44, i45, i46, i47, i48, i49, i50, i51,
i52, i53, i54, i55, i56, i57, i58, i59, i60, i61, i62, i63, i64, i65,
i66, i67, i68, i69, i70, i71, i72, i73, i74, i75, i76, i77, i78, i79,
i80, i81, i82, i83, i84, i85, i86, i87, i88, i89, i90, i91, i92, i93,
i94, i95, i96, i97, i98, i99;

// Can have more than two inputs, three in this case.
nand n1(my_output, i0, i1, i2);

// Or 100 if that's what you want.
xor x1(my_other_output, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9,
i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23,
i24, i25, i26, i27, i28, i29, i30, i31, i32, i33, i34, i35, i36, i37,
i38, i39, i40, i41, i42, i43, i44, i45, i46, i47, i48, i49, i50, i51,
i52, i53, i54, i55, i56, i57, i58, i59, i60, i61, i62, i63, i64, i65,
i66, i67, i68, i69, i70, i71, i72, i73, i74, i75, i76, i77, i78, i79,
i80, i81, i82, i83, i84, i85, i86, i87, i88, i89, i90, i91, i92, i93,
i94, i95, i96, i97, i98, i99);

// Remember: Don't use primitives unless they are required.

endmodule

// :Example:
//
// A binary full adder described two ways, using expressions
// (bfa_implicit) and using primitives (bfa_primitive). There is
// no advantage to using primitives.

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

// Note "^" is the exclusive or operator.
assign  sum = a ^ b ^ cin;
assign  cout = a & b | a & cin | b & cin;

endmodule

module bfa_primitive
( output uwire sum, cout,
input uwire a, b, cin );

uwire   term001, term010, term100,term111;
uwire   ab, bc, ac;
uwire   na, nb, nc;

or o1(sum,term001,term010,term100,term111);
or o2(cout,ab,bc,ac);

and a1(term001,na,nb,cin);
and a2(term010,na,b,nc);
and a3(term100,a,nb,nc);
and a4(term111,a,b,cin);

not n1(na,a);
not n2(nb,b);
not n3(nc,cin);

and a10(ab,a,b);
and a11(bc,b,cin);
and a12(ac,a,cin);

endmodule

////////////////////////////////////////////////////////////////////////////////
/// Module Connections

// :SV12: Section 23.2

// The connections in and out of a module are declared in the module header.
//
// There are two styles for module headers, ANSI and non-ANSI.
//   ANSI is used in classroom examples.
//   Non-ANSI is used in older versions of Verilog.

/// Port Connections
//
//   These specify signals entering or leaving the module,
//    or variables shared with the instantiating module.

/// Parameter Constant Connections
//
//   These are constants that are specified when instantiating a module
//   They might specify the number of bits in a uwire, optional behavior, etc.

module shift_left                   // <-  Module name.
// Parameter Constant List (Below)
#( int wi = 32,
int wo = wi )
// TTT NN FFFF

// Port List (Below)
( output uwire [wo-1:0] shifted,
input  uwire [wi-1:0] unshifted,
input  uwire [\$clog2(wo):0] amt );
//DDDDD  KKKK SIZE          NAME

// D: Direction: :Keywords: input,output,inout,ref
// K: Kind/Type. Can be all kinds of objects. For now: uwire, logic
// S: Size. Optional. Applies to bit sized types. We'll get to that.
// N: Identifier for declared port or parameter.

// T: Data type.
// F: Default value.

assign shifted = unshifted << amt;

endmodule

/// Directions
//
// :Keywords: input,output
//
// These are used with module connections modeling hardware.
// For most assignments a direction must be one of these.
// A port declared *in* cannot be driven or assigned in the module.
// A port declared *out* cannot be driven or assigned in the instantiation.
//
// :Keyword: inout
//
// Direction inout is used with module connections modeling busses.
// Direction inout will probably never be used in this course.
//
// :Keyword: ref
//
// Direction ref is used with module connections that don't model hardware.
// It works like a reference in C++.
// It will not be used until later in the semester.

/// Parameter Constants
//
//   Constant values specified when the module is instantiated.
//   The module header provides a default value.

// :Example:
//
// Modules to compute s = c1 x + c2 y,
//   where c1 and c2 are constants.
//
//  c1x_c2y_good:   Good use of parameters to instantiate module.
//  c1x_c2y_okay:   Rely on optimization to clean things up.
//  c1x_c2y_error:  Won't work because of misuse of parameters.
//
//
// Constructed from two kinds of multiplier module:
//   mult:      Ordinary multiplier.
//   mult_by_c: Multiplies by a constant.

module mult
#( int w = 8,
int w2 = 2 * w )
( output uwire signed [w2-1:0] prod,
input uwire signed [w-1:0] a,
input uwire signed [w-1:0] b );

assign prod = a * b;

endmodule

module mult_by_c
#( int w = 8,
int b = 16,
int w2 = w+\$clog2(b) )
( output uwire signed [w2-1:0] prod,
input uwire signed [w-1:0] a );

assign prod = a * b;

endmodule

module c1x_c2y_good
#( int c1 = 7,
int c2 = 12,
int w = 15,
int w2 = w + \$clog2(c1) + \$clog2(c2) )
( output logic signed [w2-1:0] s,
input uwire signed [w-1:0] x, y );

uwire [w2-1:0] p1, p2;

mult_by_c #(w,c1,w2) m1(p1, x);
mult_by_c #(w,c2,w2) m2(p2, y);

assign  s = p1 + p2;

endmodule

module c1x_c2y_okay
#( int c1 = 7,
int c2 = 12,
int w = 15,
int w2 = w + \$clog2(c1) + \$clog2(c2) )
( output logic signed [w2-1:0] s,
input uwire signed [w-1:0] x, y );

uwire [w2-1:0] p1, p2;

mult #(w,w2) m1(p1, x, c1);
mult #(w,w2) m2(p2, y, c2);

assign  s = p1 + p2;

endmodule

`ifdef XXXX
module c1x_c2y_error
#( int w = 15,
int w2 = 2 * w )
( output logic signed [w2-1:0] s,
input uwire signed [w-1:0] x, y,
input int c1, c2 );

uwire [w2-1:0] p1, p2;

mult_by_c #(w,c1,w2) m1(p1, x);
mult_by_c #(w,c2,w2) m2(p2, y);

assign  s = p1 + p2;

endmodule
`endif

////////////////////////////////////////////////////////////////////////////////
/// Descriptive Styles

// :Def: Descriptive Style
//
//  A set of rules for writing Verilog code.
//
//  The descriptive styles here are informally defined.

// :Def: Explicit Behavioral Form
//
//  A descriptive style in which a module can not use continuous
//  assignment statements (assign) or procedural statements (code
//  within (initial and always). The module can instantiate primitives
//  and other modules.
//
//  This style is easiest for synthesis programs to work with but
//  extremely tedious to write.
//
//  The pie module above is in the explicit structural style.

// :Def: Implicit Behavioral Form
//
//  A descriptive style in which a module can not use procedural
//  statements (code within (initial and always). The module can
//  instantiate primitives and other modules, and can use continuous
//  assignments.
//
//  This style is also easy for synthesis programs to work with
//  but can be tedious to write.

// :Example:
//
// The module below is equivalent to the pie module, except that
// it is in implicit structural form.

module pie_implicit_structural
( output uwire x, y,
input uwire a, b, c );

assign x = !( a ^ b );
assign y = x && c || b;

endmodule

// :Def: Synthesizable Behavioral Form
//
// A descriptive style in which a module can use procedural code, but
// following rules for synthesizability. (Those rules are determined
// by the particular synthesis program being used.)

// :Example:
//
// The module below is equivalent to the pie module, except that
// it is in synthesis behavioral form.

module pie_behavioral
( output logic x, y,
input uwire a, b, c );

always_comb begin

x = !( a ^ b );
y = x && c || b;

end

endmodule

// :Example:
//
// Because of the \$display system task, the module below is not in
// synthesizable behavioral form, or any other descriptive style
// defined above.
//
module pie_procedural
( output logic x, y,
input uwire a, b, c );

initial
\$display("Hello, from the pie_procedural module!\n");

always_comb begin

x = !( a ^ b );
y = x && c || b;

end

endmodule

module two_pie_demo;

logic f, g, h, a;
uwire  o1, o2;

two_pie our_two_pie(o1,o2, f,g,h,a);

initial begin

f = 0;
g = 0;
h = 0;
a = 0;

#1;

f = 1;

end

endmodule```