Lecture 3: Combinational Logic in SystemVerilog UCSD ECE 111 Prof. Farinaz Koushanfar Fall 2017 Some slides are courtesy of Prof. Lin
Register Transfer Level Design Description Today’s Topic Combinational Logic Combinational Logic Slide courtesy of Prof. Kris Gaj, George Mason University Registers
Digital design building blocks
Quick list Basic Logic gates Buffers Adders Multipliers Shifters and Rotators Comparators Multiplexers Encoders Decoders
Bitwise Operators // single line comment /*…*/ multiline comment module gates(input logic [3:0] a, b, output logic [3:0] y1, y2, y3, y4, y5); /* Five different two-input logic gates acting on 4 bit busses */ assign y1 = a & b; // AND assign y2 = a | b; // OR assign y3 = a ^ b; // XOR assign y4 = ~(a & b); // NAND assign y5 = ~(a | b); // NOR endmodule // single line comment /*…*/ multiline comment Slide derived from slides by Harris & Harris from their book
HDL Synthesis SystemVerilog: module example(input logic a, b, c, output logic y); assign y = ~a & ~b & ~c | a & ~b & ~c | a & ~b & c; endmodule Synthesis: translates into a netlist (i.e., a list of gates and flip-flops, and their wiring connections) * Schematic after some logic optimization Slide derived from slides by Harris & Harris from their book
Behavioral vs. Structural Slide derived from slides by Harris & Harris from their book
Slide courtesy of Prof. Kris Gaj, GMU Signals Wires vs. Buses Merging Splitting Slide courtesy of Prof. Kris Gaj, GMU
Reduction Operator module and8(input logic [7:0] a, output logic y); assign y = &a; // &a is much easier to write than // assign y = a[7] & a[6] & a[5] & a[4] & // a[3] & a[2] & a[1] & a[0]; endmodule Slide derived from slides by Harris & Harris from their book
Conditional Assignment module mux2(input logic [3:0] d0, d1, input logic s, output logic [3:0] y); assign y = s ? d1 : d0; endmodule ? : is also called a ternary operator because it operates on 3 inputs: s, d1, and d0. Slide derived from slides by Harris & Harris from their book
Numbers Format: N'Bvalue N = number of bits, B = base N'B is optional but recommended (default is decimal) Number # Bits Base Decimal Equivalent Stored 3'b101 3 binary 5 101 'b11 unsized 00…0011 8'b11 8 00000011 8'b1010_1011 171 10101011 3'd6 decimal 6 110 6'o42 octal 34 100010 8'hAB hexadecimal 42 00…0101010 Slide derived from slides by Harris & Harris from their book
Signal Values Regular logic values Z value: X value 0 and 1 logic High impedance (open circuit) Synthesized by a tri-state buffer E.g., assign output = (output_enable) ? input : 1'bz X value Don’t care (Assigned to either 0 or 1 logic, whichever is more helpful for the optimization process ) Applicable to certain input patters that may never occur
Tri-State Buffer, tri-and, and tri-or x f e = 0 (a) A tri-state buffer x f e x f e = 1 Z x f 1 Z 1 1 1 1 (b) Equivalent circuit Tri-state courtesy of Prof. Kris Gaj, GMU (c) Truth table
Adder Example and Internal Variables module fulladder(input logic a, b, cin, output logic s, cout); logic p, g; // internal nodes assign p = a ^ b; assign g = a & b; assign s = p ^ cin; assign cout = g | (p & cin); endmodule Slide derived from slides by Harris & Harris from their book
Adder Example – Hierarchical Design /* hierarchical 4-bit adder */ module h4ba(input logic [3:0] A, B, input logic carry_in, output logic [3:0] sum, output logic carry_out); logic carry_out_0, carry_out_1, carry_out_2; // internal signals fulladder fa0 (A[0], B[0], carry_in, sum[0], carry_out_0); fulladder fa1 (A[1], B[1], carry_out_0, sum[1], carry_out_1); fulladder fa2 (A[2], B[2], carry_out_1, sum[2], carry_out_2); fulladder fa3 (A[3], B[3], carry_out_2, sum[3], carry_out); endmodule each of these is an instantiation of “full_adder”
Adder Example module add4(input logic [3:0] A, B, output logic [3:0] sum); assign sum = A + B; endmodule Verilog compilers will replace arithmetic operators with default logic implementations (e.g. ripple carry adder) this expands into logic for a ripple carry adder
Bit Manipulations: Example 1 assign y = {a[2:1], {3{b[0]}}, a[0], 6'b100_010}; // if y is a 12-bit signal, the above statement produces: y = a[2] a[1] b[0] b[0] b[0] a[0] 1 0 0 0 1 0 // underscores (_) are used for formatting only to make it easier to read. SystemVerilog ignores them. Slide derived from slides by Harris & Harris from their book
Bit Manipulations: Example 2 module mux2_8(input logic [7:0] d0, d1, input logic s, output logic [7:0] y); mux2 lsbmux(d0[3:0], d1[3:0], s, y[3:0]); mux2 msbmux(d0[7:4], d1[7:4], s, y[7:4]); endmodule Slide derived from slides by Harris & Harris from their book
More Examples module ex1(input logic [3:0] X, Y, Z, input logic a, cin, output logic [3:0] R1, R2, R3, Q1, Q2, output logic [7:0] P1, P2, output logic t, cout); assign R1 = X | (Y & ~Z); assign t = &X; assign R2 = (a == 1’b0) ? X : Y; assign P1 = 8’hff; assign P2 = {{4{a}, X[3:2], Y[1:0]); assign {cout, R3} = X + Y + cin; assign Q1 = X << 2; assign Q2 = {X[1], X[0], 1’b0, 1’b0}; endmodule use of bitwise Boolean operators example reduction operator conditional operator example constants replication, same as {a, a, a, a} example concatenation bit shift operator equivalent bit shift
Parameterized Modules 2:1 mux: module pmux2 #(parameter width = 8) // name and default value (input logic [width-1:0] d0, d1, input logic s, output logic [width-1:0] y); assign y = s ? d1 : d0; endmodule Instance with 8-bit bus width (uses default): pmux2 pmux2_8(d0, d1, s, out); Instance with 12-bit bus width: pmux2 #(12) pmux2_12 (d0, d1, s, out); Slide derived from slides by Harris & Harris from their book
Combinational Logic Using Always
Combinational Logic Using Always Slide derived from slides by Harris & Harris from their book
Combinational Logic Using Always /* behaviorial description of a 4-bit adder */ module p4ba(input logic [3:0] A, B, input logic carry_in, output logic [3:0] sum, output logic carry_out); logic [4:0] carry; // internal signal always_comb begin carry[0] = carry_in; for (int i = 0; i < 4; i++) begin sum[i] = A[i] ^ B[i] ^ carry[i]; carry[i+1] = A[i] & B[i] | A[i] & carry[i] | B[i] & carry[i]; end carry_out = carry[4]; endmodule entire “always_comb” block is called an “always statement” for combiantional logic for loops must have a specified range. simply interpreted as “replication”. Note we can declare the loop control variable within the for loop Verilog calls the use of “=“ inside an always statement as a “blocking” assignment. all it means is that the Verilog will “parse” the lines of code inside the always block in “sequential” order in the generation of logic. (will make more sense later when we discuss “non-blocking” assignments.)
Combinational Logic Using Always
Combinational Multiplication Long Hand Procedure Review // Multiply 5 times 12 in binary: // // 0101 Multiplicand // 1100 Multiplier // """" // 0000 // 0000 // 0101 // 0101 // """"""" // 0111100 Product
Combinational Multiplication Code module simple_combinational_mult(product,multiplier,multiplicand); //P input [15:0] multiplier, multiplicand; output product; reg [31:0] product; integer i; always @( multiplier or multiplicand ) begin product = 0; for(i=0; i<16; i=i+1) if( multiplier[i] == 1'b1 ) product = product + ( multiplicand << i ); end endmodule
Arithmetic Operators Summary module Arithmetic (A, B, Y1, Y2, Y3, Y4, Y5); input [2:0] A, B; output [3:0] Y1; output [4:0] Y3; output [2:0] Y2, Y4, Y5; reg [3:0] Y1; reg [4:0] Y3; reg [2:0] Y2, Y4, Y5; always @(A or B) begin Y1=A+B; //addition Y2=A-B; //subtraction Y3=A*B; //multiplication Y4=A/B; //division Y5=A%B; //modulus of A divided by B end endmodule
Sign Operators These operators simply assign a positive "+" or negative "-" sign to a singular operand. Usually no sign operators is defined, in which case the default "+" is assumed module Sign (A, B, Y1, Y2, Y3); input [2:0] A, B; output [3:0] Y1, Y2, Y3; reg [3:0] Y1, Y2, Y3; always @(A or B) begin Y1=+A/-B; Y2=-A+-B; Y3=A*-B; end endmodule
Relational Operators Relational operators compare two operands and returns an indication of whether the compared relationship is true or false module Relational (A, B, Y1, Y2, Y3, Y4); input [2:0] A, B; output Y1, Y2, Y3, Y4; reg Y1, Y2, Y3, Y4; always @(A or B) begin Y1=A<B;//less than Y2=A<=B;//less than or equal to Y3=A>B;//greater than if (A>B) Y4=1; else Y4=0; end endmodule
Equality and Inequality Equality and inequality operators are used in exactly the same way as relational operators and return a true or false indication module Equality (A, B, Y1, Y2, Y3); input [2:0] A, B; output Y1, Y2; output [2:0] Y3; reg Y1, Y2; reg [2:0] Y3; always @(A or B) begin Y1=A==B;//Y1=1 if A equivalent to B Y2=A!=B;//Y2=1 if A not equivalent to B if (A==B)//parenthesis needed Y3=A; else Y3=B; end endmodule
Relational Operators Logical comparison operators are used in conjuction with relational and equality operators. They provide a means to perform multiple comparisons within a a single expression module Logical (A, B, C, D, E, F, Y); input [2:0] A, B, C, D, E, F; output Y; reg Y; always @(A or B or C or D or E or F) begin if ((A==B) && ((C>D) || !(E<F))) Y=1; else Y=0; end endmodule
Bitwise Operators Logical bit-wise operators take two single or multiple operands on either side of the operator and return a single bit result. The only exception is the NOT operator. Note System Verilog doesn’t have NAND or NOR module Bitwise (A, B, Y); input [6:0] A; input [5:0] B; output [6:0] Y; reg [6:0] Y; always @(A or B) begin Y(0)=A(0)&B(0); //binary AND Y(1)=A(1)|B(1); //binary OR Y(2)=!(A(2)&B(2)); //negated AND Y(3)=!(A(3)|B(3)); //negated OR Y(4)=A(4)^B(4); //binary XOR Y(5)=A(5)~^B(5); //binary XNOR Y(6)=!A(6); //unary negation end endmodule
Shift Shift operators require two operands. The operand before the operator contains data to be shifted and the operand after contains the number of single bit shift operations to be performed. 0 is for filling the blanks module Shift (A, Y1, Y2); input [7:0] A; output [7:0] Y1, Y2; parameter B=3; reg [7:0] Y1, Y2; always @(A) begin Y1=A<<B; //logical shift left Y2=A>>B; //logical shift right end endmodule
Concatenation and Replication The concatenation operator "{ , }" combines (concatenates) the bits of two or more data objects. The objects may be scalar (single bit) or vectored (muliple bit). Mutiple concatenations may be performed (a.k.a., replication) module Concatenation (A, B, Y); input [2:0] A, B; output [14:0] Y; parameter C=3'b011; reg [14:0] Y; always @(A or B) begin Y={A, B, (2{C}}, 3'b110}; end endmodule
More on Reduction SystemVerilog has six reduction operators, these operators accept a single vectored (multiple bit) operand, performs the appropriate bit-wise reduction on all bits of the operand, and returns a single bit result module Reduction (A, Y1, Y2, Y3, Y4, Y5, Y6); input [3:0] A; output Y1, Y2, Y3, Y4, Y5, Y6; reg Y1, Y2, Y3, Y4, Y5, Y6; always @(A) begin Y1=&A; //reduction AND Y2=|A; //reduction OR Y3=~&A; //reduction NAND Y4=~|A; //reduction NOR Y5=^A; //reduction XOR Y6=~^A; //reduction XNOR end endmodule
Conditional An expression using conditional operator evaluates the logical expression before the "?". If the expression is true then the expression before the colon (:) is evaluated and assigned to the output module Conditional (Time, Y); input [2:0] Time; output [2:0] Y; reg [2:0] Y; parameter Zero =3b'000; parameter TimeOut = 3b'110; always @(Time) begin Y=(Time!=TimeOut) ? Time +1 : Zero; end endmodule
If-else Statement Equivalent statement module MUX(O, I0, I1, S); input [7:0] I0, I1; input S; output reg [7:0] O; always(*) begin if (S) O = I1; else O = I0; end endmodule module MUX(O, I0, I1, S); input [7:0] I0, I1; input S; output reg [7:0] O; assign O = S? I1 : I0; endmodule Equivalent statement ECE 111 Fall 2017
Case Statement module MUX(O, I0, I1, S); input [7:0] I0, I1; input S; output reg [7:0] O; always(*) begin case(S) 0 : O = I0; 1 : O = I1; default : O = I0; endcase end endmodule ECE 111 Fall 2017
Multiplexers Multiplexers are realized using conditional operators – can be cascaded module mux5( select, d, q ); input[1:0] select; input[3:0] d; output q; wire q; wire[1:0] select; wire[3:0] d; assign q = ( select == 0 )? d[0] : ( select == 1 )? d[1] : ( select == 2 )? d[2] : d[3]; endmodule
Behavioral modeling by Verilog Operators
Precedence Order of operations ~ NOT *, /, % mult, div, mod +, - Highest ~ NOT *, /, % mult, div, mod +, - add,sub <<, >> shift <<<, >>> arithmetic shift <, <=, >, >= comparison ==, != equal, not equal &, ~& AND, NAND ^, ~^ XOR, XNOR |, ~| OR, NOR ?: ternary operator Lowest Slide derived from slides by Harris & Harris from their book
Decoder module dec2x4(A,D); input [1:0] A; output[3:0] D; reg[3:0] D; always @(A) begin if (A ==8'b00) D=4'b0001; else if (A ==8'b01) D=4'b0010; else if (A ==8'b10) D=4'b0100; else if (A ==8'b11) D=4'b1000; end endmodule A0 A1
Priority Encoder module encoder (D, Q); input [7:0] D; output [2:0] Q; reg [2:0] Q; always @(D) begin if (D ==8'b00000001) dout=3'b000; else if (D==8'b0000001 X) Q=3'b001; else if (D==8'b000001 XX) Q=3'b010; else if (D==8'b00001XXX) Q=3'b011; else if (D==8'b0001XXXX) Q=3'b100; else if (D==8'b001XXXXX) Q=3'b101; else if (D==8'b01XXXXXX) Q=3'b110; else if (D==8'b1XXXXXXX) Q=3'b111; else Q=3'bX; end endmodule
Combinational logic using case module sevenseg(input logic [3:0] data, output logic [6:0] segments); always_comb case (data) // abc_defg 0: segments = 7'b111_1110; 1: segments = 7'b011_0000; 2: segments = 7'b110_1101; 3: segments = 7'b111_1001; 4: segments = 7'b011_0011; 5: segments = 7'b101_1011; 6: segments = 7'b101_1111; 7: segments = 7'b111_0000; 8: segments = 7'b111_1111; 9: segments = 7'b111_0011; default: segments = 7'b000_0000; // required endcase endmodule case statement translates into a more complex “multiplexor” similar to if-then-else Slide derived from slides by Harris & Harris from their book
Combinational logic using case case statement implies combinational logic only if all possible input combinations described Remember to use default statement Otherwise, compiler will create an “asynchronous latch” to remember previous value: bad because this is not intended! Slide derived from slides by Harris & Harris from their book
Combinational logic using casez module priority_casez(input logic [3:0] a, output logic [3:0] y); always_comb casez(a) 4'b1???: y = 4'b1000; // ? = don’t care 4'b01??: y = 4'b0100; 4'b001?: y = 4'b0010; 4'b0001: y = 4'b0001; default: y = 4'b0000; endcase endmodule Slide derived from slides by Harris & Harris from their book
Nesting In general, for loop, if-then-else, and case statements can be “nested”. e.g., for (…) if (…) case (…) … endcase else … Compiler will compile from the “inner-most” scope outwards: i.e., it will first produce multiplexor logic for “case” statement, then produce multiplexor logic for the “if-then-else” part, then replicate all that logic based on the number of iterations in the “for loop”.
What we have learned today… Various SystemVerilog Operators Using always statement to implement combinational logic Using case statement for combinational logic Seven segment display by combinational logic and case statement UCSD ECE 111, Prof. Koushanfar, Fall'16