//LSU EE 3755 – Fall 2009 Computer Organization

//

/// Verilog Notes 2 -- Expressions

 

/// Contents

 

// Continuous Assignment

// Operators:  Bitwise Logical

// Vectors, Bit Selects, and Part Select

// Sized Numbers and Constants (Parameters)

// Operators: Bitwise with Vectors

// Operators: Arithmetic

// Operators: Logical AND, etc

/// References

 

// :P:   Palnitkar, "Verilog HDL"

// :Q:   Qualis, "Verilog HDL Quick Reference Card Revision 1.0"

// :PH:  Patterson & Hennessy, "Computer Organization & Design"

 

 

 

////////////////////////////////////////////////////////////////////////////////

/// Continuous Assignment

 

// :P: 6.1    

// Continuous assignment specifies a value for a wire using an

// expression.

//

//

// Continuous assignments can be made using the /assign/ keyword and in a

// wire [or other net] declaration.

 

// :Keyword: assign

//

// :Sample:  assign a = b;

//

// Here "b" is the expression.

// The left hand side of an assignment always should be a wire[net].

// :Example:

//

// A simple use of the assign keyword.  Output x is given

// the value of "a".  Whenever "a" changes "x" also changes.

// Don't forget that: Whenever "a" changes "x" also changes.

//

// The module below passes the signal through unchanged.

 

module really_simple(x,a);

   input a;

   output x;

 

   assign x = a;

 

endmodule

 

 

// :Example:

//

// The module below is functionally equivalent to the one above.

 

module really_simple_with_a_gate(x,a);

   input a;

   output x;

 

   and a1(x,a);

  

endmodule

 

 

// :Example:

//

// The module below also passes a signal through the module unchanged,

// but this time it goes through an extra wire, w.  Whenever "a"

// changes, w will change and that will change x.

 

module something_similar(x,a);

   input a;

   output x;

 

   wire   w;

 

   assign w = a;

   assign x = w;

 

endmodule

 

 

// :Example:

//

// The module below is like the one above except that

// continuous assignment to w is done in the wire declaration

// rather than with a separate assign statement.

 

module something_else_similar(x,a);

   input a;

   output x;

 

   wire   w = a;

   assign x = w;

 

endmodule

 

 

 

////////////////////////////////////////////////////////////////////////////////

/// Operators:  Bitwise Logical

 

// :P: 6.3,6.4

// :P: 6.4.5  

// Operators for performing bitwise logical operations.

//

// (The meaning of bitwise and logical will be explained in the Vector

// section below.)

//

//

// Operators:

//  &  bitwise and

//  |  bitwise or

//  ~  bitwise not

//  ^  bitwise exclusive or

 

 

// :Example:

//

// A module implementing: x = ab + c;

 

module my_abc_module(x,a,b,c);

   input a, b, c;

   output x;

 

   assign x = a & b | c;

 

endmodule

 

 

// :Example:

//

// The module below is functionally equivalent but less readable than

// the one above.

 

module my_abc_module_gates(x,a,b,c);

   input a, b, c;

   output x;

 

   wire   ab;

  

   and a1(ab,a,b);

   or o1(x,ab,c);

 

endmodule

 

 

// :Example:

//

// Simple uses of the &, |, and ~ operators along with truth tables.

 

module operator_demo(x1,x2,x3,x4,a,b);

   input a, b;

   output x1, x2, x3, x4;

 

   // Bitwise AND.  (There is also a logical AND, discussed later.)

   //

   assign x1 = a & b;

   //

   // a  b  |  a & b

   // """"""""""""""

   // 0  0  |    0

   // 0  1  |    0

   // 1  0  |    0

   // 1  1  |    1

 

   // Bitwise OR.  (There is also a logical OR, discussed later.)

   //

   assign x2 = a | b;

   //

   // a  b  |  a | b

   // """"""""""""""

   // 0  0  |    0

   // 0  1  |    1

   // 1  0  |    1

   // 1  1  |    1

 

   // Bitwise XOR.

   //

   assign x3 = a ^ b;

   //

   // a  b  |  a ^ b

   // """"""""""""""

   // 0  0  |    0

   // 0  1  |    1

   // 1  0  |    1

   // 1  1  |    0

 

   // Bitwise NOT;

   //

   assign x4 = ~a;

   //

   // a   |  ~a

   // """"""""""""

   // 0   |   1

   // 1   |   0

 

endmodule

 

 

// :Example:

//

// A binary-full adder using operators.  Some consider this more

// readable than the earlier version.  Note how spaces and returns

// (whitespace) are used to make the assignment to sum readable.

 

module bfa_implicit(sum,cout,a,b,cin);

   input a,b,cin;

   output sum,cout;

 

   assign sum =

          ~a & ~b &  cin |

          ~a &  b & ~cin |

           a & ~b & ~cin |

           a &  b &  cin;

 

   assign cout = a & b | b & cin | a & cin;

 

endmodule

 

 

 

////////////////////////////////////////////////////////////////////////////////

/// Vectors, Bit Selects, and Part Select

 

// :P: 3.2.4  

/// Vectors

//

// So far only 1-bit wires have been shown.

//

// A /vector/ is a wire [or reg] that is more than one bit.

//

// The size and the bit numbering are specified in the declaration.

// (See examples.)

 

// :Sample:  wire [10:0] a;

// :Sample:  output [10:0] b;

//

// Declares wire a and output b with least-significant bit 0 and

// most-significant bit 10 (for a total of 11 bits).

 

 

 /// Bit and Part Selects

//

// A bit select is used to extract a single bit from a wire [or reg].

// :Sample:  assign x = a[1]; // Extract bit 1.

//

// A part select is used to extract several consecutive bits from a

// wire [or reg].

// :Sample:  assign y = a[5:3]; // Set y to 3 bits of a, bits 5 to 3.

 

 

// :Example:

 

// This example does not use vectors. The author, who knew nothing

// about vectors, wanted a 4-bit input "a" and a 4-bit output x,

// plus a one-bit output msb.

 

module without_vectors(msb,x3,x2,x1,x0,a3,a2,a1,a0);

   output msb;

   output x3, x2, x1, x0;

   input  a3, a2, a1, a0;

 

   assign msb = a3;

   assign x3 = a3;

   assign x2 = a2;

   assign x1 = a1;

   assign x0 = a0;

 

endmodule

 

 

// :Example:

//

// This is the way the module above should be done.  Here input "a"

// and output "x" are declared as 4-bit vectors.  A bit select

// is used in the assignment to msb.

 

module with_vectors(msb,x,a);

   output msb;

   // Declare x as a 4-bit input, bit 3 is the most-significant bit (MSB).

   output [3:0] x;

   input  [3:0] a;

 

   assign       msb = a[3];  // Extract bit 3 from a, which is the MSB.

   assign       x = a;

 

endmodule

 

 

// :Example:

//

// This module does the same thing as the one above.  It is written

// differently: 0 is used to indicate the MSB (rather than 3).  Some

// prefer that the MSB be the highest-numbered bit, some like it to be

// the lowest-numbered bit.

 

module more_vectors(msb,x,a);

   output msb;

   output [0:3] x; // Here MSB is 0 and LSB is 3.

   input  [0:3] a;

 

   assign       msb = a[0];

   assign       x = a;

 

endmodule

 

 

// :Example:

//

// Here the vector declaration is used in a wire, rather than

// a port (input or output).

 

module and_more_vectors(x,a);

   input [15:0] a;

   output [15:0] x;

 

   wire [15:0]   w;

 

   assign        w = a;

   assign        x = w;

 

endmodule

 

 

////////////////////////////////////////////////////////////////////////////////

/// Sized Numbers and Constants (Parameters)

 

// :P: 3.1.4, 3.2.8 

 

 /// Sized Numbers

//

// In Verilog numbers can be written with a specific size and using

// one of four radices (bases).

 

// The number consists of a size (in bits) followed by an apostrophe,

// followed by a b,o,d, or h (for binary, octal, decimal,

// hexadecimal), followed by the number.

//

// :Sample: 16'd5

//

// The number five using 16 bits written in decimal.

//

// :Sample: 16'b101

//

// The number five represented using 16 bits written in binary.

 

 /// Constants

//

// Constants are specified using the /parameter/ keyword.

//

// :Sample:  parameter limit = 5;

//

// This specifies a parameter named limit with a value of 5.

// Identifier limit can be used in expressions but cannot be

// assigned.  For more information see parameter_examples module

// below.

 

// :Keyword:

// parameter

 

// :Example:

//

// The number one and the number ten are specified in a variety of

// ways.  Note the size of the wires and that each wire is assigned

// multiple times. (In this class, one should not assign the same wire

// multiple times. [Elsewhere, it might be done if the wire is a bus

// and is driven by tri-state devices.])

 

module fixed(one,ten);

 

   output [7:0] one;

   output [15:0] ten;

 

   // All assignments below do the same thing. 

   //

   // Use the one that's easiest to read.

   //

   assign        one = 1;     // No size specified.

   assign        one = 8'b1;  // One specified in binary.

   assign        one = 8'b00000001;  // One specified in binary.

   assign        one = 4'b1;  // Sloppy, but works: Specified wrong size.

   assign        one = 8'd1;  // One specified in decimal.

   assign        one = 8'h1;  // One specified in hexadecimal;

 

   // All assignments below do the same thing.

   //

   // Use the one that's easiest to read.

   //

   assign        ten = 10;

   assign        ten = 16'b1010;

   assign        ten = 16'b0000000000001010;

   assign        ten = 16'd10;

   assign        ten = 16'ha;

   assign        ten = 16'h000a;

 

endmodule

 

 

// :Example:

//

// A sized number is used to specify the carry in of one of the bfa's

// in a two-bit ripple adder.  It's important to use a sized number

// (rather than a regular number) for connections to modules.

 

module ripple_2(sum,cout,a,b);

   input [1:0] a, b;

   output [1:0] sum;

   output       cout;

 

   wire         c0;

 

   bfa_implicit bfa0(sum[0],c0,a[0],b[0],1'b0);

   bfa_implicit bfa1(sum[1],cout,a[1],b[1],c0);

 

endmodule

 

 

// :Example:

//

// A module illustrating the use of parameters (as constants).

 

module parameter_examples(an_input);

   input [7:0] an_input;

 

   parameter one = 1;

 

   // Parameters can be sized numbers.

   parameter two = 10'd2;

 

   // The value of seconds_per_day is computed once, at analysis

   // (usually compile) time.

   parameter seconds_per_day = 60 * 60 * 24;

 

   parameter width = 12;

   parameter height = 21;

   // The value of area is computed once, at analysis

   // (usually compile) time.

   parameter area = width * height;

 

   // The line below is an error because "an_input" is not a constant.

   // parameter double_input = an_input * two;

 

endmodule

 

 

 

////////////////////////////////////////////////////////////////////////////////

/// Operators:  Bitwise with Vectors

 

// The same references as the earlier bitwise logical section.

//

// :P: 6.3,6.4

// :P: 6.4.5  

 

 

// Operators &, |, ~, ^ are called /bitwise/ because when

// the operands are vectors the operation is done on each

// bit of the vector.

 

// :Example:

//

// An appropriate use of a bitwise operator, followed by

// code that does the same thing the hard way.

 

module and_again(x1,a,b);

   input [2:0] a, b;   // Both a and b are 3 bits.

   output [2:0] x1;

 

   // An appropriate use.

   //

   // Bitwise AND, but this time operands are 3-bit vectors.

   //

   assign x1 = a & b;  // ANDs three pairs of bits.

 

   // The same thing the hard way:

   //

   assign x1[0] = a[0] & b[0];

   assign x1[1] = a[1] & b[1];

   assign x1[2] = a[2] & b[2];

   //

   // Examples:

   //

   // a    b    |  a & b

   // """"""""""""""

   // 000  000  |  000

   // 000  001  |  000

   // 010  111  |  010

   // 100  110  |  100

 

endmodule

 

 

////////////////////////////////////////////////////////////////////////////////

/// Operators: Arithmetic

 

// :P: 6.4.1

//

 

// The arithmetic operators are:

//   + (addition), - (subtraction), * (multiplication), / (division),

//   and % (remainder).

 

// They operate on wires and data types to be covered later.

 

 

// :Example:

//

// A simple demonstration of arithmetic operators.

 

module arith_op(sum,diff,prod,quot,rem,a,b);

   input [15:0] a, b;

   output [15:0] sum, diff, prod, quot, rem;

 

   // For these operators vectors are interpreted as integers.

 

   // Addition

   assign sum = a + b;

 

   // Subtraction

   assign diff = a - b;

 

   // Multiplication

   assign prod = a * b;

 

   // Division

   assign quot = a / b;

 

   // Remainder (Modulo)

   assign rem = a % b;

   //

   // Examples:

   //

   // a    b    |  a % b

   // """"""""""""""""""

   // 3    5    |  3

   // 5    3    |  2

   // 7    7    |  0

 

endmodule

 

 

// :Example:

//

// The input to the module below is a complex number (specified

// with a real and imaginary part); the output is the square

// of that number.

 

module complex_square(sr,si,ar,ai);

   input [31:0] ar, ai;

   output [31:0] sr, si;

 

   assign       sr = ar * ar - ai * ai;

   assign       si = 2 * ar * ai;

 

   // Notes on code above:

   //

   // Multiplication has higher precedence than subtraction and so

   // subtraction done last.

   //

   // A constant is used in the si expression.

 

endmodule

 

 

 

////////////////////////////////////////////////////////////////////////////////

/// Operators: Logical AND, etc

 

// :P: 6.4.2

// There is a logical AND operator, &&, that is different than

// the bitwise AND, &.

// Likewise there is a logical OR, ||, and a logical NOT, !.

 

// See the example.

 

 

// :Example:

//

// Illustration of logical operators, and how they are different than

// the bitwise operators.

 

module and_again_again(x1,x2,x3,x4,a,b);

   input [2:0] a, b;   // Both a and b are 3 bits.

   output [2:0] x1;

   output       x2, x3, x4;

 

   // Bitwise AND, but this time operands are 3-bit vectors.

   //

   assign x1 = a & b;  // ANDs three pairs of bits.

   //

   // The same thing the hard way:

   //

   assign x1[0] = a[0] & b[0];

   assign x1[1] = a[1] & b[1];

   assign x1[2] = a[2] & b[2];

   //

   // Examples:

   //

   // a    b    |  a & b

   // """"""""""""""""""

   // 000  000  |  000

   // 000  001  |  000

   // 010  111  |  010

   // 100  110  |  100

 

   // Logical AND. (Not to be confused with bitwise AND!)

   //

   assign x2 = a && b;

   //

   // Here both a and b are 3 bits, but x2 is a single bit.

   // Wire a is treated as logical true if any bit is 1;

   // it is treated as logical false if all bits are 0.

   //

   // Therefore x2 is set to 1 if a and b are true and to zero

   // if a or b is false.

   //

   // Examples:

   //

   // a    b    |  a && b

   // """"""""""""""""""

   // 000  000  |  0

   // 000  001  |  0

   // 010  101  |  1

   // 100  110  |  1

 

   // Logical OR. (Not to be confused with bitwise OR.)

   //

   assign x3 = a || b;

   //

   // Operands are treated as logical values as described for &&.

   //

   // Wire x3 is set to 1 if a or b is true and to zero

   // if a and b are false.

   //

   // Examples:

   //

   // a    b    |  a || b

   // """"""""""""""""""

   // 000  000  |  0

   // 000  001  |  1

   // 010  101  |  1

   // 100  110  |  1

 

   // Logical NOT.

   //

   assign x4 = !a;

   //

   // Wire x4 is set to zero if any bit in a is 1,

   // x4 is set to one if all bits in a are zero.

 

endmodule