4. Finite state machine

4.1. Introduction

Note

  • In previous chapters, we saw the various examples of combinational and sequential designs. In this chapter, we will learn to use the finite state machines to implement various types of designs.
  • The proper methods for implementing the various kinds of FSM designs are disucssed in the Verilog/VHDL tutorials. In this chapter, we will re-implement the designs of the Chapter “Finite state machines” in the Verilog/VHDL tutorial. Please see the Verilog/SystemVerilog/VHDL tutorials for the explanation of the designs.

4.2. Rising edge detector

  • In the below code, the rising edge detector is implemented using Mealy and Moore designs,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    # edge_detector.py
    # the results are same as "edgeDetector.v" in the Verilog tutorial
    
    from myhdl import *
    
    @block
    def edge_detector(clk, reset_n, level, mealy_tick, moore_tick):
    
        # mealy states
        mealy_states = enum('zero_mealy', 'one_mealy')
        state_mealy_reg = Signal(mealy_states.zero_mealy)
        state_mealy_next = Signal(mealy_states.zero_mealy)
    
        # moore states
        moore_states = enum('zero_moore', 'edge_moore', 'one_moore')
        state_moore_reg = Signal(moore_states.zero_moore)
        state_moore_next = Signal(moore_states.zero_moore)
    
        # current state logic
        @always(clk.posedge, reset_n.negedge)
        def state_current_logic():
            if reset_n == 0 :
                state_moore_reg.next = moore_states.zero_moore
                state_mealy_reg.next = mealy_states.zero_mealy
            else :
                state_moore_reg.next = state_moore_next
                state_mealy_reg.next = state_mealy_next
    
        # next state logic : Mealy design
        @always_comb
        def state_next_logic_mealy():
            state_mealy_next.next = state_mealy_reg
            mealy_tick.next = 0
            if state_mealy_reg == mealy_states.zero_mealy :
                if level == 1 :
                    state_mealy_next.next = mealy_states.one_mealy
                    mealy_tick.next = 1
            elif state_mealy_reg == mealy_states.one_mealy:
                if level != 1 :
                    state_mealy_next.next = mealy_states.zero_mealy
    
        # next state logic : Moore design
        @always_comb
        def state_next_logic_moore():
    
            state_moore_next.next = state_moore_reg
            moore_tick.next = 0
            if state_moore_reg == moore_states.zero_moore :
                if level == 1 :
                    state_moore_next.next = moore_states.edge_moore
            elif state_moore_reg == moore_states.edge_moore:
                moore_tick.next = 1
                if level == 1 :
                    state_moore_next.next = moore_states.one_moore
                else :
                    state_moore_next.next = moore_states.zero_moore
            elif state_moore_reg == moore_states.one_moore:
                if level != 1 :
                    state_moore_next.next = moore_states.zero_moore
    
    
        return state_current_logic, state_next_logic_moore, state_next_logic_mealy
    
    def main():
        clk = Signal(bool(0))
        reset_n = Signal(bool(0))
        level = Signal(bool(0))
        moore_tick = Signal(bool(0))
        mealy_tick = Signal(bool(0))
    
        edge_detector_verilog = edge_detector(clk, reset_n, level, mealy_tick, moore_tick)
        edge_detector_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__':
        main()
    
  • The resultant Verilog code is shown below,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    // File: edge_detector.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:29:53 2017
    
    
    `timescale 1ns/10ps
    
    module edge_detector (
        clk,
        reset_n,
        level,
        mealy_tick,
        moore_tick
    );
    
    
    input clk;
    input reset_n;
    input level;
    output mealy_tick;
    reg mealy_tick;
    output moore_tick;
    reg moore_tick;
    
    reg [1:0] state_moore_reg = 2'b00;
    reg [1:0] state_moore_next = 2'b00;
    reg [0:0] state_mealy_reg = 1'b0;
    reg [0:0] state_mealy_next = 1'b0;
    
    
    
    always @(posedge clk, negedge reset_n) begin: EDGE_DETECTOR_STATE_CURRENT_LOGIC
        if ((reset_n == 0)) begin
            state_moore_reg <= 2'b00;
            state_mealy_reg <= 1'b0;
        end
        else begin
            state_moore_reg <= state_moore_next;
            state_mealy_reg <= state_mealy_next;
        end
    end
    
    
    always @(state_moore_reg, level) begin: EDGE_DETECTOR_STATE_NEXT_LOGIC_MOORE
        state_moore_next = state_moore_reg;
        moore_tick = 0;
        case (state_moore_reg)
            2'b00: begin
                if ((level == 1)) begin
                    state_moore_next = 2'b01;
                end
            end
            2'b01: begin
                moore_tick = 1;
                if ((level == 1)) begin
                    state_moore_next = 2'b10;
                end
                else begin
                    state_moore_next = 2'b00;
                end
            end
            2'b10: begin
                if ((level != 1)) begin
                    state_moore_next = 2'b00;
                end
            end
        endcase
    end
    
    
    always @(level, state_mealy_reg) begin: EDGE_DETECTOR_STATE_NEXT_LOGIC_MEALY
        state_mealy_next = state_mealy_reg;
        mealy_tick = 0;
        case (state_mealy_reg)
            1'b0: begin
                if ((level == 1)) begin
                    state_mealy_next = 1'b1;
                    mealy_tick = 1;
                end
            end
            1'b1: begin
                if ((level != 1)) begin
                    state_mealy_next = 1'b0;
                end
            end
        endcase
    end
    
    endmodule
    

4.3. Non overlapping sequence detector : 110

  • In the below code, a sequence detector is implement which detects the sequence ‘110’,

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    # sequence_detector.py
    # result is same as the listing "sequence_detector.v" in verilog tutorial
    
    from myhdl import *
    
    @block
    def sequence_detector(clk, reset_n, x, z_mealy_glitch, z_moore_glitch,
            z_mealy_glitch_free, z_moore_glitch_free):
    
    
        # mealy states
        mealy_states = enum('zero_mealy', 'one_mealy', 'two_mealy', 'three_mealy')
        state_mealy_reg = Signal(mealy_states.zero_mealy)
        state_mealy_next = Signal(mealy_states.zero_mealy)
    
        # moore states
        moore_states = enum('zero_moore', 'one_moore', 'two_moore', 'three_moore')
        state_moore_reg = Signal(moore_states.zero_moore)
        state_moore_next = Signal(moore_states.zero_moore)
    
        z_moore = Signal(bool(0))
        z_mealy = Signal(bool(0))
    
        @always(clk.posedge, reset_n.negedge)
        def current_state_logic():
            if reset_n == 0 :
                state_mealy_reg.next = mealy_states.zero_mealy
                state_moore_reg.next = moore_states.zero_moore
            else :
                state_mealy_reg.next = state_mealy_next
                state_moore_reg.next = state_moore_next
    
        # next state mealy logic
        @always_comb
        def next_state_logic_mealy():
            z_mealy.next = 0
            state_mealy_next.next = state_mealy_reg
            if state_mealy_reg == mealy_states.zero_mealy:
                if x == 1 :
                    state_mealy_next.next = mealy_states.one_mealy
            elif state_mealy_reg == mealy_states.one_mealy :
                if x == 1 :
                    state_mealy_next.next = mealy_states.two_mealy
                else :
                    state_mealy_next.next = mealy_states.zero_mealy
            elif state_mealy_reg == mealy_states.two_mealy :
                state_mealy_next.next = mealy_states.zero_mealy
                if x == 0 :
                    z_mealy.next = 1
                else :
                    state_mealy_next.next = mealy_states.two_mealy
    
        # next state moore logic
        @always_comb
        def next_state_logic_moore():
            z_moore.next = 0
            state_moore_next.next = state_moore_reg
            if state_moore_reg == moore_states.zero_moore:
                if x == 1 :
                    state_moore_next.next = moore_states.one_moore
            elif state_moore_reg == moore_states.one_moore :
                if x == 1 :
                    state_moore_next.next = moore_states.two_moore
                else :
                    state_moore_next.next = moore_states.zero_moore
            elif state_moore_reg == moore_states.two_moore :
                if x == 0 :
                    state_moore_next.next = moore_states.three_moore
                else :
                    state_moore_next.next = moore_states.two_moore
            elif state_moore_reg == moore_states.three_moore :
                z_moore.next = 1
                if x == 1 :
                    state_moore_next.next = moore_states.zero_moore
                else :
                    state_moore_next.next = moore_states.one_moore
    
    
        @always_comb
        def assign_outputs():
            z_mealy_glitch.next = z_mealy
            z_moore_glitch.next = z_moore
    
        @always(clk.posedge, reset_n.negedge)
        def glitch_free_output():
            if reset_n == 1 :
                z_mealy_glitch_free.next = 0
                z_moore_glitch_free.next = 0
            else :
                z_mealy_glitch_free.next = z_mealy
                z_moore_glitch_free.next = z_moore
    
    
        return current_state_logic, next_state_logic_mealy, \
                next_state_logic_moore, assign_outputs, glitch_free_output
    
    def main():
        clk = Signal(bool(0))
        reset_n = Signal(bool(0))
        x = Signal(bool(0))
        z_mealy_glitch = Signal(bool(0))
        z_moore_glitch = Signal(bool(0))
        z_mealy_glitch_free = Signal(bool(0))
        z_moore_glitch_free = Signal(bool(0))
    
        sequence_detector_verilog = sequence_detector(clk, reset_n, x,
                z_mealy_glitch, z_moore_glitch,
                z_mealy_glitch_free, z_moore_glitch_free)
    
        sequence_detector_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__':
        main()
    
  • The corresponding Verilog design is shown below,

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    // File: sequence_detector.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:33:20 2017
    
    
    `timescale 1ns/10ps
    
    module sequence_detector (
        clk,
        reset_n,
        x,
        z_mealy_glitch,
        z_moore_glitch,
        z_mealy_glitch_free,
        z_moore_glitch_free
    );
    
    
    input clk;
    input reset_n;
    input x;
    output z_mealy_glitch;
    wire z_mealy_glitch;
    output z_moore_glitch;
    wire z_moore_glitch;
    output z_mealy_glitch_free;
    reg z_mealy_glitch_free;
    output z_moore_glitch_free;
    reg z_moore_glitch_free;
    
    reg z_moore = 0;
    reg z_mealy = 0;
    reg [1:0] state_moore_reg = 2'b00;
    reg [1:0] state_moore_next = 2'b00;
    reg [1:0] state_mealy_reg = 2'b00;
    reg [1:0] state_mealy_next = 2'b00;
    
    
    
    always @(posedge clk, negedge reset_n) begin: SEQUENCE_DETECTOR_CURRENT_STATE_LOGIC
        if ((reset_n == 0)) begin
            state_mealy_reg <= 2'b00;
            state_moore_reg <= 2'b00;
        end
        else begin
            state_mealy_reg <= state_mealy_next;
            state_moore_reg <= state_moore_next;
        end
    end
    
    
    always @(x, state_mealy_reg) begin: SEQUENCE_DETECTOR_NEXT_STATE_LOGIC_MEALY
        z_mealy = 0;
        state_mealy_next = state_mealy_reg;
        case (state_mealy_reg)
            2'b00: begin
                if ((x == 1)) begin
                    state_mealy_next = 2'b01;
                end
            end
            2'b01: begin
                if ((x == 1)) begin
                    state_mealy_next = 2'b10;
                end
                else begin
                    state_mealy_next = 2'b00;
                end
            end
            2'b10: begin
                state_mealy_next = 2'b00;
                if ((x == 0)) begin
                    z_mealy = 1;
                end
                else begin
                    state_mealy_next = 2'b10;
                end
            end
        endcase
    end
    
    
    always @(x, state_moore_reg) begin: SEQUENCE_DETECTOR_NEXT_STATE_LOGIC_MOORE
        z_moore = 0;
        state_moore_next = state_moore_reg;
        case (state_moore_reg)
            2'b00: begin
                if ((x == 1)) begin
                    state_moore_next = 2'b01;
                end
            end
            2'b01: begin
                if ((x == 1)) begin
                    state_moore_next = 2'b10;
                end
                else begin
                    state_moore_next = 2'b00;
                end
            end
            2'b10: begin
                if ((x == 0)) begin
                    state_moore_next = 2'b11;
                end
                else begin
                    state_moore_next = 2'b10;
                end
            end
            2'b11: begin
                z_moore = 1;
                if ((x == 1)) begin
                    state_moore_next = 2'b00;
                end
                else begin
                    state_moore_next = 2'b01;
                end
            end
        endcase
    end
    
    
    
    assign z_mealy_glitch = z_mealy;
    assign z_moore_glitch = z_moore;
    
    
    always @(posedge clk, negedge reset_n) begin: SEQUENCE_DETECTOR_GLITCH_FREE_OUTPUT
        if ((reset_n == 1)) begin
            z_mealy_glitch_free <= 0;
            z_moore_glitch_free <= 0;
        end
        else begin
            z_mealy_glitch_free <= z_mealy;
            z_moore_glitch_free <= z_moore;
        end
    end
    
    endmodule
    

4.4. Timed FSM - programmable square wave

  • In the below code, the square wave is generated with programmable on/off time,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    # square_wave_ex.py
    # results are same as Listing "square_wave_ex.v" in Verilog tutorial
    
    from myhdl import *
    
    @block
    def square_wave_ex(clk, reset_n, s_wave, on_time, off_time, N):
        states = enum('on_state', 'off_state')
        state_reg = Signal(states.on_state)
        state_next = Signal(states.on_state)
        t = Signal(intbv(0)[N:0])
    
        @always(clk.posedge, reset_n.negedge)
        def current_state_logic():
            if reset_n == 0 :
                state_reg.next = states.off_state
            else :
                state_reg.next = state_next
    
        @always(clk.posedge, reset_n.negedge)
        def timer_logic():
            if state_reg != state_next :
                t.next = 0
            else :
                t.next = t + 1
    
        @always_comb
        def next_state_logic():
            if state_reg == states.off_state :
                s_wave.next = 0
                if t == off_time - 1 :
                    state_next.next = states.on_state
                else :
                    state_next.next = states.off_state
            if state_reg == states.on_state :
                s_wave.next = 1
                if t == on_time - 1 :
                    state_next.next = states.off_state
                else :
                    state_next.next = states.on_state
    
        return current_state_logic, timer_logic, next_state_logic
    
    def main():
        N = 4
        on_time = 5
        off_time = 3
        clk = Signal(bool(0))
        reset_n = Signal(bool(0))
        s_wave = Signal(bool(0))
    
        square_wave_verilog = square_wave_ex(clk, reset_n,
                s_wave, on_time, off_time, N)
    
        square_wave_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__':
        main()
    
  • Following is the generated Verilog code,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    // File: square_wave_ex.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:39:35 2017
    
    
    `timescale 1ns/10ps
    
    module square_wave_ex (
        clk,
        reset_n,
        s_wave
    );
    
    
    input clk;
    input reset_n;
    output s_wave;
    reg s_wave;
    
    reg [3:0] t = 0;
    reg [0:0] state_reg = 1'b0;
    reg [0:0] state_next = 1'b0;
    
    
    
    always @(posedge clk, negedge reset_n) begin: SQUARE_WAVE_EX_CURRENT_STATE_LOGIC
        if ((reset_n == 0)) begin
            state_reg <= 1'b1;
        end
        else begin
            state_reg <= state_next;
        end
    end
    
    
    always @(posedge clk, negedge reset_n) begin: SQUARE_WAVE_EX_TIMER_LOGIC
        if ((state_reg != state_next)) begin
            t <= 0;
        end
        else begin
            t <= (t + 1);
        end
    end
    
    
    always @(t, state_reg) begin: SQUARE_WAVE_EX_NEXT_STATE_LOGIC
        if ((state_reg == 1'b1)) begin
            s_wave = 0;
            if (($signed({1'b0, t}) == (3 - 1))) begin
                state_next = 1'b0;
            end
            else begin
                state_next = 1'b1;
            end
        end
        if ((state_reg == 1'b0)) begin
            s_wave = 1;
            if (($signed({1'b0, t}) == (5 - 1))) begin
                state_next = 1'b1;
            end
            else begin
                state_next = 1'b0;
            end
        end
    end
    
    endmodule
    

4.5. Mod-m counter

  • In the below code, the Mod-m counter is implemented using FSM method,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # counter_ex.py
    # results are same as the Listing 'counter_ex.v' in Verilog tutorial
    
    from myhdl import *
    
    @block
    def counter_ex(clk, reset_n, out_moore, M, N):
        states = enum('start_moore', 'count_moore')
        state_moore_reg = Signal(states.start_moore)
        state_moore_next = Signal(states.start_moore)
    
        count_moore_reg = Signal(intbv(0)[N:0])
        count_moore_next = Signal(intbv(0)[N:0])
    
        @always(clk.posedge, reset_n.negedge)
        def current_state_logic():
            if reset_n == 0 :
                state_moore_reg.next = states.start_moore
                count_moore_reg.next = 0
            else :
                state_moore_reg.next = state_moore_next
                count_moore_reg.next = count_moore_next
    
        @always_comb
        def next_state_logic():
            if state_moore_reg == states.start_moore :
                count_moore_next.next = 0
                state_moore_next.next = states.count_moore
            elif state_moore_reg == states.count_moore :
                count_moore_next.next = count_moore_reg + 1
                if count_moore_reg + 1 == M - 1 :
                    state_moore_next.next = states.start_moore
                else :
                    state_moore_next.next = states.count_moore
    
        @always_comb
        def assign_output_logic():
            out_moore.next = count_moore_reg
    
        return current_state_logic, next_state_logic, assign_output_logic
    
    def main():
        M = 6
        N = 4
        clk = Signal(bool(0))
        reset_n = Signal(bool(0))
        out_moore = Signal(bool(0))
    
        counter_ex_verilog = counter_ex(clk, reset_n, out_moore, M, N)
        counter_ex_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__':
        main()
    
  • Following is the resultant Verilog code,

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    // File: counter_ex.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:43:20 2017
    
    
    `timescale 1ns/10ps
    
    module counter_ex (
        clk,
        reset_n,
        out_moore
    );
    
    
    input clk;
    input reset_n;
    output out_moore;
    wire out_moore;
    
    reg [0:0] state_moore_reg = 1'b0;
    reg [0:0] state_moore_next = 1'b0;
    reg [3:0] count_moore_reg = 0;
    reg [3:0] count_moore_next = 0;
    
    
    
    always @(posedge clk, negedge reset_n) begin: COUNTER_EX_CURRENT_STATE_LOGIC
        if ((reset_n == 0)) begin
            state_moore_reg <= 1'b0;
            count_moore_reg <= 0;
        end
        else begin
            state_moore_reg <= state_moore_next;
            count_moore_reg <= count_moore_next;
        end
    end
    
    
    always @(count_moore_reg, state_moore_reg) begin: COUNTER_EX_NEXT_STATE_LOGIC
        case (state_moore_reg)
            1'b0: begin
                count_moore_next = 0;
                state_moore_next = 1'b1;
            end
            1'b1: begin
                count_moore_next = (count_moore_reg + 1);
                if (((count_moore_reg + 1) == (6 - 1))) begin
                    state_moore_next = 1'b0;
                end
                else begin
                    state_moore_next = 1'b1;
                end
            end
        endcase
    end
    
    
    
    assign out_moore = count_moore_reg;
    
    endmodule
    

4.6. Conclusion

In this chapter, we implemented various FSM designs using MyHDL. We followed the FSM-design-rules which are discussed in Verilog/SystemVerilog/VHDL tutorials. Further, the resultant Verilog and VHDL codes are exactly same as the Verilog/VHDL tutorial.