600 likes | 610 Views
Explore Verilog operators, behavioral modeling concepts, data types, and assign statements in logic design. Learn about combinational & sequential logic design principles.
E N D
COE 405 Logic Design with Behavioral Models of Combinational & Sequential Logic Dr. Aiman H. El-Maleh Computer Engineering Department King Fahd University of Petroleum & Minerals
Outline • Behavioral Modeling • Data Types for Behavioral Modeling • Assign Statement • Verilog Operators • Always Block, Procedural Assignment • If and Case Statements • Latches & D Flip-Flops • Data Flow / Register Transfer Level (RTL) • Behavioral Modeling of Control Unit • Registers & Counters
Behavioral Modeling • Behavioral modeling describes the functionality of a design • What the design will do • Not how the design will be built in hardware • Behavioral models specify the input-output model of a logic circuit and suppress details about its low level internal structure. • Behavioral modeling encourages designers to • Rapidly create a behavioral prototype of a design • Verify its functionality • Use synthesis tool to optimize and map design into a given technology
Data Types for Behavioral Modeling • All variables in Verilog have a predefined type. • There are two families of data types: nets and registers. • Net variables act like wires in physical circuit and establish connectivity between design objects. • Net types include: wire, tri, wand, wor, triand, trior, supply0, supply1, tri0, tri1, trireg.
Data Types for Behavioral Modeling • Register variables act like variables in ordinary procedural languages – they store information while the program executes. • Register types include: reg, integer, real, realtime, time. • For synthesis, we use mainly the data types wire, reg and integer. • A wire and a reg have a default size of 1 bit. • Size of integer is the size of word length in a computer, at least 32. • A reg variable may never be the output of a primitive gate, the target of continuous assignment.
Assign Statement • The keyword assign declares a continuous assignment. • It associates the Boolean expression on the RHS with the variable on the LHS. • The assignment is sensitive to the variables in the RHS. • Any time an event occurs on any of the variables on the RHS, the RHS expression is revaluated and the result is used to update the LHS. • A continuous assignment is said to describe implicit combinational logic.
Assign Statement module AOI_5_CA1 ( input x_in1, x_in2, x_in3, x_in4, x_in5, enable, output y_out ); assign y_out = enable ? !((x_in1 && x_in2) || (x_in3 && x_in4 && x_in5)) : 1’bz; endmodule
Assign Statement • The conditional operator (?:) acts like a software if-then-else switch that selects between two expressions. • If the value of enable is true, the expression to the right of the ? Is evaluated and used to assign value to y_out. • Otherwise, the expression to the right of the : is used. • Using 1’bz illustrates how to write models that include three-state outputs. • A module may contain multiple continuous assignments; the assignments are active concurrently with all other continuous assignments, primitives, behavioral statements, and instantiated modules.
Assign Statement module Mux_2_32_CA #(parameter wordsize=32) ( output [wordsize-1:0] mux_out, input [wordsize-1:0] data_1, data_0, input select ); assign mux_out = select ? data_1 : data_0; endmodule
Verilog Operators { } concatenation + - * / ** arithmetic % modulus > >= < <= relational ! logical NOT && logical AND || logical OR == logical equality != logical inequality === case equality !== case inequality ? : conditional ~ bit-wise NOT & bit-wise AND | bit-wise OR ^ bit-wise XOR ^~ ~^ bit-wise XNOR & reduction AND | reduction OR ~& reduction NAND ~| reduction NOR ^ reduction XOR ~^ ^~ reduction XNOR << shift left >> shift right
Verilog Operators • Arithmetic Operators: • Each operator takes two operands. + and – could also take a single operand • During synthesis, the + and - operators infer an adder and a subtractor • Xilinx XST software can infer a block multiplier during synthesis for the multiplication operator • /, %, and ** operators usually cannot be synthesized automatically • Shift operators: Four shift operators • >>, << logical shift right and left (0s inserted from the right or the left) • >>>,<<<arithmetic shift right and left (sign bits are shifted in for the >>> operation and 0's are shifted in for the <<< operation)
Verilog Operators • If both operands of a shift operator are signals, as in a << b, the operator infers a barrel shifter, a fairly complex circuit • If the shifted amount is fixed, as in a << 2, the operation infers no logic and involves only routing of the input signals (can also be done with {} operator) • Examples of shift operations:
Verilog Operators • Relational and equality operators: • compare two operands and return a 1-bit logical (Boolean) value: either 0 or 1 • 4 relational operators: >, <, <=, and >= • 4 equality operators: ==, !=, ===, and !== • Case equality (===) and case inequality (!==) operators, take the x and z bits in the operands into consideration in the match cannot be synthesized. • The relational operators and the == and != operators infer comparators during synthesis
Verilog Operators • Bitwise operators: • 4 basic bitwise operators: & (and), I (or), ^ (xor), and ! (not) • The first three operators require two operands • Negation and xor operation can be combined, as in ~^ or ^~ to form the xnor • Operations are performed on a bit-by-bit basis • Ex.: let a, b, and c be 4-bit signals: i.e. wire [3:0] a , b , c ; The statement: assign c = a I b ; is the same as: assign c[3] = a[3] I b[3]; assign c[2] = a[2] I b[2]; assign c[1] = a[1] I b[1]; assign c[0] = a[0] I b[0];
Verilog Operators • Reduction operators: &, I , and ^ operators may have only one operand and hence are known as reduction operators. • The single operand usually has an array data type. • The designated operation is performed on all elements of the array and returns a 1-bit result. • For example, let a be a 4-bit signal and y be a 1-bit signal: wire [3:0] a ; wire y ; The statement: assign y = I a ; // only one operand is the same as: assign y = a[3] | a[2] | a[1] | a[0] ;
Verilog Operators • Logical operators: && (logical and), II (logical or), and ! (logical negate) • Operands of a logical operator are interpreted as false (when all bits are 0's) or true (when at least one bit is 1), and the operation always returns a 1-bit result • Usually used as logical connectives of Boolean expressions, • Bitwise and logical operators can be used interchangeably in some situations. • Examples of bitwise and logical operations
Verilog Operators • Conditional operator: ? : takes three operands and its general format is [signal] = [boolean-exp] ? [true-exp] : [false-exp]; • The [boolean-expl] is a Boolean expression that returns true (1’b1) or false ( 1'b0). • Ex.: assign max = (a>b) ? a : b; //max will get the maximum of the signals a and b • The operator can be thought as a simplified if-then-else statement. Infers a mux. • Can be cascaded or nested: assign max = (a>b) ? ((a>c) ? a : c) : ((b>c) ? b : c ) ; // max of three signals
Verilog Operators • Concatenation and replication operators: { } and {{ }} • { } combines segments of elements and small arrays to form a large array: wire a1; wire [3:0] a4; wire [7:0] b8, c8, d8; assign b8 = {a4 , a4} ; assign c8 = {a1, a1, a4, 2'b00 } ; assign d8 = {b8[3:0] , c8[3:0]} ; • Concatenation operator involves reconnection of the input and output signals and only requires "wiring”. Can be used for shifting or rotating data.
Verilog Operators wire [7:0] a, rot, shl , sha; assign rot = {a[2:0], a[7:3]} ; // Rotate a to right 3 bits assign shl = {3'b000, a[7:3]} ; // shift a to right 3 bits and insert 0s (logical shift) assign sha = {a[7] , a[7] , a[7] , a[7:3]} ; // arithmeticshift a to right 3 bits • The replication operator, N{ }, replicates the enclosed string. The replication constant, N, specifies the number of replications. For example: {4{2'b01}} returns 8'b01010101.
Behavioral Description of an Adder module adder #(parameter width = 4) (output cout, output [width-1:0] sum, input [width-1:0] a, b, input cin); assign {cout, sum} = a + b + cin; // note: Verilog treats wires as ‘unsigned’ numbers endmodule 4-bit operands, 5-bit result { Cout, S } is a 5 bit bus: Cout S[3] S[2] S[1] S[0]
Always Block • always blocks are procedural blocks that contain sequential statements. • Syntax always @(sensitivity list) begin ………. end • sensitivity list prevents the always block from executing again until another change occurs on a signal in the sensitivity list. • Level type • always @(a or b or c) • Edge type • always @(posedge clock) • always @(negedge clock)
Procedural Assignment • Assignments inside an always block are called procedural assignments • Can only be used within an always block or initial block • Two types : blocking assignment and nonblocking assignment. Basic syntax : • [variable-name] = [expression] ; // blocking assignment • [variable-name] <= [expression] ; // nonblocking assignment • In a blocking assignment, the expression is evaluated and then assigned to the variable immediately, before execution of the next statement (the assignment thus "blocks" the execution of other statements). It behaves like the normal variable assignment in the C language.
Procedural Assignment • In a nonblocking assignment, the evaluated expression is assigned at the end of the always block (the assignment thus does not block the execution of other statements). • The basic rule of thumb is: • Use blocking assignments for a combinational circuit. • Use nonblocking assignments for a sequential circuit. • if-else and case statement are only in always block.
Wire vs. Reg • There are two types of variables in Verilog: • wire (all outputs of assign statements must be wire) • reg (all outputs modified in always blocks must be reg) • Both variables can be used as inputs anywhere • Can use reg or wire as inputs (RHS) to assign statements • assign bus = LatchOutput + ImmediateValue • // bus must be a wire, but LatchOutput can be a reg • Can use reg or wire as inputs (RHS) in always blocks • always @ (in or clk) • if (clk) out = in // in can be a wire, out must be a reg
Algorithm-Based Models • Algorithms prescribe a sequence of procedural assignments within a cyclic behavior. • The algorithm described by the model does not have explicit binding to hardware. • It does not have an implied architecture of registers, datapaths and computational resources. • This style is most challenging for a synthesis tool. • Synthesis tool needs to perform architectural synthesis which extracts the needed resources and schedules them into clock cycles.
If Statements Syntax if (expression) begin ...procedural statements... end else if (expression) begin ...statements... end ...more else if blocks else begin ...statements... end module ALU #(parameter n=8) (output reg [n-1:0] c, input [1:0] s, input [n-1:0] a, b); always @(s or a or b) begin if (s==2'b00) c = a + b; else if (s==2'b01) c = a - b; else if (s==2'b10) c = a & b; else c = a | b; end endmodule
Case Statements Syntax case (expression) case_choice1: begin ...statements... end case_choice2: begin ...statements... end ...more case choices blocks... default: begin ...statements... end endcase module ALU2 #(parameter n=8) (output reg [n-1:0] c, input [1:0] s, input [n-1:0] a, b); always @(s or a or b) begin case (s) 2'b00: c = a + b; 2'b01: c = a - b; 2'b10: c = a & b; default: c = a | b; endcase end endmodule
Example: Full Adder module fadd2 (output reg S, Cout, input A, B, Cin); always @(A or B or Cin) begin S = (A ^ B ^ Cin); Cout = (A & B) | (A & Cin) | (B & Cin); end endmodule
Example: Comparator module comp #(parameter width=32) (input [width-1:0] A, B, output A_gt_B, A_lt_B, A_eq_B); assign A_gt_B = (A>B); assign A_lt_B = (A<B); assign A_eq_B = (A==B); endmodule
Example: Comparator module comp2 #(parameter width=2) (input [width-1:0] A, B, output reg A_gt_B, A_lt_B, A_eq_B); always @(A, B) begin A_gt_B = 0; A_lt_B = 0; A_eq_B = 0; if (A == B) A_eq_B = 1; else if (A > B) A_gt_B = 1; else A_lt_B = 1; end endmodule
Example: 2x1 Multiplexer • Method 1 module mux2x1 (input b, c, select, output a); assign a = (select ? b : c); endmodule • Method 2 module mux2x1 (input b, c, select, output reg a); always@(select or b or c) begin if (select) a=b; else a=c; end endmodule Method 3 module mux2x1 (input b, c, select, output rega); always@(select or b or c) begin case (select) 1’b1: a=b; 1’b0: a=c; endcase end endmodule
Example: DeMux module demux ( input D, select, output reg y0, y1); always @( D or select ) begin if( select == 1’b0) begin y0 = D; y1 = 1’b0; end else begin y0 = 1’b0; y1 = D; end end endmodule
Example: Arithmetic Unit module arithmetic #(parameter width=8) (input [width-1:0] A, B, input [1:0] Sel, output reg [width-1:0] Y, output reg Cout); always @(A or B or Sel) begin case (Sel) 2'b 00 : {Cout,Y} = A+B; 2'b 01 : {Cout,Y} = A-B; 2'b 10 : {Cout,Y} = A+1; 2'b 11 : {Cout,Y} = A-1; default: begin Cout=0; Y=0; end endcase end endmodule
Example: Logic Unit module logic #(parameter width=4) (input [width-1:0] A, B, input [2:0] Sel, output reg [width-1:0] Y); always @(A or B or Sel) begin case (Sel) 3'b 000 : Y = A & B; // A and B 3'b 001 : Y = A | B; // A or B 3'b 010 : Y = A ^ B; // A xor B 3'b 011 : Y = ~A; // 1’s complement of A 3'b 100 : Y = ~(A & B); // A nand B 3'b 101 : Y = ~(A | B); // A nor B default : Y = 0; endcase end endmodule
Latches & Level-Sensitive Circuits • Latch can be modeled as: module latch (output q, qb, input set, reset); assign q = ~(set & qb); assign qb = ~(reset & q); endmodule • Some synthesis tools do not accommodate this form of feedback. • Latch is inferred by synthesis tools as follows: module dlatch (output q, input data_in, enable); assign q = enable ? data_in : q; endmodule module dlatch2 (output q, input data_in, enable, reset); assign q = (reset==1'b0)? 0: enable ? data_in : q; endmodule
D Latch module dlatch (output q, input data, enable); assign q = enable ? data: q; endmodule module dlatch2 (output reg q, input data, enable); always @(enable, data) if (enable == 1'b1) q <= data; endmodule
D Flip Flop – Synchronous Set/Reset module dff (output reg q, output q_bar, input data, set_b, reset_b, clk); assign q_bar = !q; always @(posedge clk) // Synchronous set/reset if (reset_b == 1'b0) q <= 0; else if (set_b == 1'b0) q <=1; else q <= data; endmodule
D Flip Flop – Asynchronous Set/Reset module dff2 (output reg q, output q_bar, input data, set_b, reset_b, clk); assign q_bar = !q; always @(posedge clk, negedge set_b, negedge reset_b ) // Asynchronous set/reset if (reset_b == 1'b0) q <= 0; else if (set_b == 1'b0) q <=1; else q <= data; endmodule
Data Flow/ RTL Models • Data flow models describe concurrent operations on signals where computations are initiated at active edges of a clock and completed to be stored in a register at next active edge. • Also referred to as Register Transfer Level (RTL) as they describe transfer of data among registers. • A behavioral model of combinational logic can be described using concurrent assign statements or always statements. • A behavioral model of sequential logic can be described using always statements.
Shift Register module shiftreg (output reg A, input E, clk, rst); reg B, C, D; always @(posedge clk, posedge rst) begin if (rst == 1'b1) begin A=0; B=0; C=0; D=0; end else begin A = B; B = C; C = D; D = E; end end endmodule
Shift Register module shiftreg2 (output reg A, input E, clk, rst); reg B, C, D; always @(posedge clk, posedge rst) begin if (rst == 1'b1) begin A=0; B=0; C=0; D=0; end else begin D = E; C = D; B = C; A = B; end end endmodule What will happen in this model?
Shift Register module shiftreg3 (output reg A, input E, clk, rst); reg B, C, D; always @(posedge clk, posedge rst) begin if (rst == 1'b1) begin A<=0; B<=0; C<=0; D<=0; end else begin A <= B; B <= C; C <= D; D <= E; end end endmodule Non-blocking assignments (<=) execute concurrently. So they are order independent.
Behavioral Models of Multiplexor module Mux_4_1 #(parameter width=32) (output [width-1:0] mux_out, input [width-1:0] data_3, data_2, data_1, data_0, input [1:0] select, input enable); reg [width-1:0] mux_int; assign mux_out = enable ? mux_int : 'bz; always @(data_3, data_2, data_1, data_0, select) case (select) 0: mux_int = data_0; 1: mux_int = data_1; 2: mux_int = data_2; 3: mux_int = data_3; default: mux_int = 'bx; endcase endmodule
Behavioral Models of Multiplexor module Mux_4_1_IF #(parameter width=32) (output [width-1:0] mux_out, input [width-1:0] data_3, data_2, data_1, data_0, input [1:0] select, input enable); reg [width-1:0] mux_int; assign mux_out = enable ? mux_int : 'bz; always @(data_3, data_2, data_1, data_0, select) if (select==0) mux_int = data_0; else if (select==1) mux_int = data_1; else if (select==2) mux_int = data_2; else if (select==3) mux_int = data_3; else mux_int = 'bx; endmodule
Behavioral Models of Multiplexor module Mux_4_1_CA #(parameter width=32) (output [width-1:0] mux_out, input [width-1:0] data_3, data_2, data_1, data_0, input [1:0] select, input enable); wire [width-1:0] mux_int; assign mux_out = enable ? mux_int : 'bz; assign mux_int = (select==0) ? data_0: (select==1) ? data_1: (select==2) ? data_2: (select==3) ? data_3: 'bx; endmodule
Behavioral Models of Encoder module encoder (output reg [2:0] Code, input [7:0] Data); always @(Data) if (Data==8'b00000001) Code = 0; else if (Data==8'b00000010) Code = 1; else if (Data==8'b00000100) Code = 2; else if (Data==8'b00001000) Code = 3; else if (Data==8'b00010000) Code = 4; else if (Data==8'b00100000) Code = 5; else if (Data==8'b01000000) Code = 6; else if (Data==8'b10000000) Code = 7; else Code = 'bx; endmodule
Behavioral Models of Encoder module priority (output reg [2:0] Code, output valid_data, input [7:0] Data); assign valid_data = | Data; always @(Data) if (Data[7]) Code = 7; else if (Data[6]) Code = 6; else if (Data[5]) Code = 5; else if (Data[4]) Code = 4; else if (Data[3]) Code = 3; else if (Data[2]) Code = 2; else if (Data[1]) Code = 1; else if (Data[0]) Code = 0; else Code = 'bx; endmodule
Behavioral Models of Encoder module priority2 (output reg [2:0] Code, output valid_data, input [7:0] Data); assign valid_data = | Data; always @(Data) casex (Data) 8'b1xxxxxxx : Code = 7; 8'b01xxxxxx : Code = 6; 8'b001xxxxx : Code = 5; 8'b0001xxxx : Code = 4; 8'b00001xxx : Code = 3; 8'b000001xx : Code = 2; 8'b0000001x : Code = 1; 8'b00000001 : Code = 0; default: Code = 'bx; endcase endmodule casex treats x values in the inputs as don’t care
Behavioral Models of Decoder module decoder (output reg [7:0] Data, input [2:0] Code); always @(Code) if (Code == 0 ) Data= 8'b00000001; else if (Code == 1 ) Data= 8'b00000010; else if (Code == 2 ) Data= 8'b00000100; else if (Code == 3 ) Data= 8'b00001000; else if (Code == 4 ) Data= 8'b00010000; else if (Code == 5 ) Data= 8'b00100000; else if (Code == 6 ) Data= 8'b01000000; else if (Code == 7 ) Data= 8'b10000000; else Data = 'bx; endmodule
Seven Segment Display Decoder module Seven_Segment_Display (output reg [6:0] Display, input [3:0] BCD); parameter BLANK = 7’b111_1111; parameter ZERO= 7’b000_0001; // abc_defg parameter ONE= 7’b100_1111; parameter TWO= 7’b001_0010; parameter THREE= 7’b000_0110; parameter FOUR= 7’b100_1100; parameter FIVE= 7’b010_0100; parameter SIX= 7’b010_0000; parameter SEVEN= 7’b000_1111; parameter EIGHT= 7’b000_0000; parameter NINE= 7’b000_0100; always @(BCD) case (BCD) 0: Display = ZERO; 1: Display = ONE; 2: Display = TWO; 3: Display = THREE; 4: Display = FOUR; 5 : Display = FIVE; 6: Display = SIX; 7: Display = SEVEN; 8: Display = EIGHT; 9: Display = NINE; default: Display = BLANK; endcase endmodule