Workshop Topics - Outline Workshop 1 - Introduction Workshop 2 - module instantiation Workshop 3 - Lexical conventions Workshop 4 - Value Logic System Workshop 5 - Data types A Workshop 6 - Data types B Workshop 7 - Operators Workshop 8 - Signed arithmetic Workshop 9 - Behavioral modeling A Workshop 10 - Behavioral modeling B Workshop 11 - Behavioral modeling C Workshop 12 - Data flow modeling Workshop 13 - Coding Styles 1 Timing Control mechanism Timing control provides a way to specify simulation time at which procedural statements will execute. Without timing control statements, simulation time does not advance. Three methods of behavioral timing control constructs, are available in Verilog: Delay-based Timing Control - # Inter (regular) and Intra-Statement Delay statements Event-based Timing Control - @ ; // edge-sensitive Regular – posedge, negedge , Named – event, Event OR control – (a or b or ..), Level-sensitive – wait statement // level-sensitive 2 Delay-based Timing Control Delay Control (#) - Expression specifies the time duration between initially encounter a statement and when statement actually executed. Procedural Assignments delay examples: #10 A = A + 1 ; // Inter-Statement . A inc 10 time units (tus) from now A = #10 A + 1 ; // Intra-Statement. A evaluated now, inc 10 tus later Examples – Regular (inter) Delay Control: parameter latency = 20 ; parameter delta = 2 ; // Define parameters reg x, y, z, p, q ; // define register variables initial begin x=0; // No delay control #10 y = 1 ; // Delay control with number #latency z = 0 ; // Delay control with identifier #(latency + delta) p = 1 ; // Delay control with expression #y x = x + 1 ; // Delay control with identifier #(4:5:6) q = 0 ; // min., typ. and max. delay values end 3 Event-based Timing Control Event is a change in value on register or a net There are 4 types of event-based timing control: Regular, Named, OR, Level-sensitive. The symbol @ is used to specify an event control Statements can be executed on changes in signal value or at a positive or negative transition of the signal value Keywords posedge/negedge are used for positive/negative transitions Regular event control: @(clk) q = d ; // q = d is executed whenever clk changes value @(posedge clk) q = d ; // q = d is executed on clk positive transition @(negedge clk) q = d ; // q = d is executed on clk negative transition q = @(negedge clk) d ; /* d is evaluated immediately and assigned to q at the negative edge of clock */ 4 Named event control An event can be declared and then triggered at the occurrence of that event. A named event is declared by the keyword event. Event does not hold any data. event is triggered by the symbol -> Triggering of the event is recognized by the symbol @. // A data buffer stores data. After the last data packet has arrived, event received_data ; // define an event called received_data always @(posedge clock) // check at each positive clock edge begin if (last_data_packet) // If this is the last data packet ->received_data ; // trigger the event received_data end always @(received_data) /* Wait for triggered received_data event. When the event is triggered, store all 4 packets of received data in data buffer. Use concatenation operator { } */ data_buf = {data_pkt[0], data_pkt[1], data_pkt[2], data_pkt[3]} ; 5 Event OR and Edge-sensitive Control Transition of any one of multiple signals or events can trigger execution of a statement or a block of statements The list of events or signals is also known as a sensitivity list The keyword or [or “,” or (*)] is used to specify multiple triggers always @(reset or en or d) ; // D latch with reset begin // wait for reset or en or d to change if (reset) // if reset signal is high, set q to 0 q <= 1’b0 ; else if (en) // data latch enabled q <= d ; end always @(posedge clk, negedge nrst) /* DFF with asynchronous reset. Executed whenever clk swings to 1 or nrst swings to 0 */ begin if (!nrst) // nrst: active low reset q <= 1’b0 ; else q <= d ; end 6 Level-sensitive Time Control - Wait Statement Wait statement waits for its conditional expression to become true before a statement or a block of statements is executed. Level sensitive is primary used for synchronizing two concurrent processes. The keyword wait is used for level-sensitive constructs. Example: always wait (count_enable) #20 count = count + 1 ; // The value of count_enable is monitored continuously. If count_enable = 0, the statement is not entered. If it is logical 1, the statement is executed after 20 time units. If count_enable stays at 1, count will be incremented every 20 time units. 7 Conditional Statements - If, else Used to make decisions based upon certain conditions. Keywords if and else are used for conditional statements. Syntax: - if <expression> true statement ; - if <expression> true statement ; else false statement ; - if <expression1> true statement1 ; // many alternatives else if <expression2> true statement2 ; else if <expression3> true statement3 ; ………… else default statement ; 8 Conditional Statement example - BCD Adder module BCDadder (sum, cout, a, b, cin) ; input [3:0] a, b ; Input cin ; output reg [3:0] sum ; output reg cout ; reg [4:0] z ; always @(a or b or cin) begin z = a + b + cin ; // assume z = 1011 (11 decimal) if (z > 9) {cout, sum} = z + 6 ; // 1011 + 0110 = 1_0001 = 11d else {cout, sum} = z ; end endmodule 9 Multi-way Branching - case Having many alternatives, using nested if-else-if is not practical. An easier way is to use the case statement The keywords case, endcase and default are used. Comparisons in a case statement are made bit by bit. No break statement is needed - first match executes and then case is exited. If not all cases are enumerated, make sure to use default case. Multi way branching - case statement syntax: case <expression> alternative1: statement1 ; alternative2: statement2 ; ……………………………………. ; default: default_statement ; // missing alternative - avoid latch endcase 10 case statement example - 2 to 4 Decoder module dec2to4 (y, w, en) ; input [1:0] w ; input en ; output reg [3:0] y ; // implicit register always @(w or en) case ({en, w}) // concatenation of en & w 3’b100: y = 4’b0001 ; 3’b101: y = 4’b0010 ; 3’b110: y = 4’b0100 ; 3’b111: y = 4’b1000 ; default: y = 4’b0000 ; // disabled module case endcase endmodule 11 case, casez, casex case treats each value 0, 1, X, and Z literally 4’b01XZ only matches 4’b01XZ Example: 4’b0110 does not match 4’b01XX in a case casez treats 0, 1, and X literally casez treats Z as a don’t care Example: 4’b0110 matches 4’b01ZZ, but not 4’b01XZ casex treats 0 and 1 literally casex // No match here treats both X and Z as don’t cares Example: 4’b0110 matches 4’b01XX and also 4’b01XZ 12 casez example module casez_example () ; reg [3:0] opcode ; reg [1:0] a, b, c, out ; always @ (opcode or a or b or c) casez(opcode) 4'b1ZZX : out = a ; /* Don't care about bits 2:1, bit 0 match with X */ 4'b01?? : out = b ; // bits 1:0 are don't care 4'b001? : out = c ; // bit 0 is don't care default : out = 2’b0 ; endcase endmodule 13 casex example – 4 to 2 Priority Encoder module priority (din, dout , valid) ; input [3:0] din ; output reg [1:0] dout ; output reg valid ; always @(din) begin valid = 1'b1 ; // assume valid output casex (din) // casex treats both x and z as don’t cares 4'b1XXX: dout = 2'b11 ; 4'b01XX: dout = 2'b10 ; 4'b001X: dout = 2'b01 ; 4'b0001: dout = 2'b00 ; default: begin valid = 1'b0 ; // non-valid output dout = 2'b0 ; // don't care case end endcase end endmodule 14 Exercise 2 Design a single bit 4 to 1 mux, employing always block and case statement. Write a Test Bench for the 4 to 1 mux. in0 in1 in2 M U X in3 2 select 15 out