Understanding Digital Logic Design

Extra materials for the combined MIPSfpga and Connected MCU seminar by Imagination Technologies

October-November 2016

Exercise 3 - Sequential design: counter, shift register, FSM

Name ___________________________________________________________________

An example introductory project: Implement a design of a shift register with enable signal. The design should input a single bit from a key and put in into the shift register. The current state and the output of the shift register should be displayed on LEDs in binary representation. In addition, the current state of the shift register should be displayed on static multi-digit seven-segment display in hexadecimal form.

3.1. Modify the counter design to count in decimal instead of hexadecimal. Not 0, 1, 2, ... 9, A, B, C, D, E, F, 10, 11, ... FFFF - but 0, 1, 2, ... 9, 10, 11, ... 9999, 0, 1, 2, ... Hint: you may need to add decimal digits separately and propagate carry.

3.2. Modify the counter design to count signed two's complement 12-bit number backwards. Output the result in hexadecimal representation with a sign: 000, -001, -002, ... -7FE, -7FF, -800, (overflow), 7FF, 7FE, 7FD, ... 002, 001, 000, -001, -002 ...

3.3. Modify the counter design to count with three different speeds, depending on pressed button.

3.4. Modify the counter design to count either forward (0, 1, 2, ...) or backward (0, FFFF, FFFE, ... , 3, 2, 1, 0, FFFF ...), depending on pressed button.

3.5. Modify the counter design to count either adding 1, or 2, or 3, depending on pressed buttons.

3.6. Modify the counter design to add disable signal that pauses counting. Connect this signal to a button.

3.7. Modify the counter design to count separately in each digit. Not 0000, 0001, 0002, ... FFFE, FFFF, 0000 - but 0000, 1111, 2222, 3333, ... EEEE, FFFF, 0000.

3.8. Modify the counter design to count separately in each two digits - 0000, 0101, 0202, ... FEFE, FFFF, 0000.

3.9. Modify the counter design to count separately in digit 3 and digits 2:0 - 0000, 1001, 2002, ... F00F, 0010, 1011, ... EFFE, FFFF, 0000.

3.10. Modify the counter design to count separately in each digit with different speed: 0000, 1234, 2468, 369C, 48C0, 5AF4, ... In other words one digit 0, 1, 2, ... F, 0; second 0, 2, 4, 6, ... E, 0; third one 0, 3, 6, 9, C, F, 2, 5, 8, B, E, 1, 4, 7, A, D, 0, fourth 0, 4, 8, C, 0, ...

3.11. Implement the design that generates Fibonnacci numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... The next number is found by adding up the two numbers before it.

3.12. Modify the shift register design to make LED lights moving not from left to right, but from right to left. Not 10011000, 01001100, 00100110, 00010011, 00001001, 00000100, ... - but 10011000, 00110000, 01100000, 11000000, ...

3.13. Modify the shift register design to make LED lights moving either from left to right or from right to left - depending on pressed button.

3.14. Modify the shift register design to make LED lights moving with different speed - depending on pressed button.

3.15. Modify the shift register design to make LED lights circularly: 10011000, 01001100, 00100110, 00010011, 10001001, 11000100, 01100010, 00110001, 10011000, ... Use one button as input, and a second button as input enable.

3.16. Modify the shift register design to make LED lights moving circularly and either from left to right or from right to left - depending on pressed button. Use one button as input, second button as input enable, and third button to control the direction of movement.

3.17. Modify the shift register design by splitting it into two independent 4-bit wide shift registers, with inputs coming from two different buttons.

3.18. Modify the shift register design by splitting it into two independent 4-bit wide shift registers, with inputs coming from the same button and with different speeds of shifting. The first should shift with the speed of one bit per clock cycle, the second - with the speed of two bits per clock cycle.

3.19. Modify the shift register design by splitting it into two independent 4-bit wide shift registers, with inputs coming from the same button and with different speeds of shifting. The first should shift with the speed of one bit per clock cycle, the second - with the speed of one bit every other cycle.

3.20. Implement a variant of exercise (18) with circular movements of LED lights. Use one button as input, and a second button as input enable.

3.21. Implement a variant of exercise (19) with circular movements of LED lights. Use one button as input, and a second button as input enable.

3.22. Implement a variant of exercise (18) with LEDs connected to the first shift register moving from left to right and LEDs connected to another one - from right to left.

3.23. Implement a variant of exercise (19) with LEDs connected to the first shift register moving from left to right and LEDs connected to another one - from right to left.

3.24. Implement a variant of exercise (22) with circular movements of LED lights. Use one button as input, and a second button as input enable.

3.25. Implement a variant of exercise (23) with circular movements of LED lights. Use one button as input, and a second button as input enable.

3.26. Modify the state machine design below by counting the occurrences of "01" sequences (i.e. counting the number of event when moore_out and mealy_out asserted). Output the number of moore_out events to the digits 3:2 of seven-segment display and the number of mealy_out events to the digits 1:0 of seven-segment display.

3.27. Modify the state machine design below to recognize the sequences of "0101" instead of "01". You need to implement only Moore machine.

3.28. Modify the state machine design below to recognize the sequences of "010101" instead of "01". You need to implement only Mealy machine.

3.29. Implement a variant of exercise 27 where you count the number of sequences instead of just recognizing them. Output the value of the counter to seven-segment display.

3.30. Implement a variant of exercise 28 where you count the number of sequences instead of just recognizing them. Output the value of the counter to seven-segment display.


Reference example:


module de0_cv
(
    input           CLOCK2_50,
    input           CLOCK3_50,
    inout           CLOCK4_50,
    input           CLOCK_50,
                   
    input           RESET_N,

    input   [ 3:0]  KEY,
    input   [ 9:0]  SW,

    output  [ 9:0]  LEDR,

    output  [ 6:0]  HEX0,
    output  [ 6:0]  HEX1,
    output  [ 6:0]  HEX2,
    output  [ 6:0]  HEX3,
    output  [ 6:0]  HEX4,
    output  [ 6:0]  HEX5,
                   
    output  [12:0]  DRAM_ADDR,
    output  [ 1:0]  DRAM_BA,
    output          DRAM_CAS_N,
    output          DRAM_CKE,
    output          DRAM_CLK,
    output          DRAM_CS_N,
    inout   [15:0]  DRAM_DQ,
    output          DRAM_LDQM,
    output          DRAM_RAS_N,
    output          DRAM_UDQM,
    output          DRAM_WE_N,
                   
    output  [ 3:0]  VGA_B,
    output  [ 3:0]  VGA_G,
    output          VGA_HS,
    output  [ 3:0]  VGA_R,
    output          VGA_VS,

    inout           PS2_CLK,
    inout           PS2_CLK2,
    inout           PS2_DAT,
    inout           PS2_DAT2,
                   
    output          SD_CLK,
    inout           SD_CMD,
    inout   [ 3:0]  SD_DATA,
                   
    inout   [35:0]  GPIO_0,
    inout   [35:0]  GPIO_1
);

    de0_cv_small de0_cv_small
    (
        .CLOCK_50 ( CLOCK_50 ),
        .RESET_N  ( RESET_N  ),

        .KEY      ( KEY      ),
        .SW       ( SW       ),

        .LEDR     ( LEDR     ),

        .HEX0     ( HEX0     ),
        .HEX1     ( HEX1     ),
        .HEX2     ( HEX2     ),
        .HEX3     ( HEX3     ),
        .HEX4     ( HEX4     ),
        .HEX5     ( HEX5     )
    );

endmodule

//----------------------------------------------------------------------------

module clock_divider_50_MHz_to_1_49_Hz
(
    input  clock_50_MHz,
    input  reset_n,
    output clock_1_49_Hz
);

    // 50 MHz / 2 ** 25 = 1.49 Hz

    reg [24:0] count;

    always @ (posedge clock_50_MHz)
    begin
        if (! reset_n)
            count <= 0;
        else
            count <= count + 1;
    end

    assign clock_1_49_Hz = count [24];

endmodule

//----------------------------------------------------------------------------

module counter_with_load
(
    input             clock,
    input             reset_n,

    input             load,
    input      [15:0] load_data,
    output reg [15:0] count
);

    always @ (posedge clock or negedge reset_n)
    begin
        if (! reset_n)
            count <= 0;
        else if (load)
            count <= load_data;
        else
            count <= count + 1;
    end

endmodule

//----------------------------------------------------------------------------

module shift_register_with_enable
(
    input            clock,
    input            reset_n,
    input            in,
    input            enable,
    output           out,
    output reg [9:0] data
);

    always @ (posedge clock or negedge reset_n)
    begin
        if (! reset_n)
            data <= 10'b10_0000_0000;
        else if (enable)
            data <= { in, data [9:1] };
    end
    
    assign out = data [0];

endmodule

//----------------------------------------------------------------------------

module single_digit_display
(
    input      [3:0] digit,
    output reg [6:0] seven_segments
);

    always @*
        case (digit)
        'h0: seven_segments = 'b1000000;  // a b c d e f g
        'h1: seven_segments = 'b1111001;
        'h2: seven_segments = 'b0100100;  //   --a--
        'h3: seven_segments = 'b0110000;  //  |     |
        'h4: seven_segments = 'b0011001;  //  f     b
        'h5: seven_segments = 'b0010010;  //  |     |
        'h6: seven_segments = 'b0000010;  //   --g--
        'h7: seven_segments = 'b1111000;  //  |     |
        'h8: seven_segments = 'b0000000;  //  e     c
        'h9: seven_segments = 'b0011000;  //  |     |
        'ha: seven_segments = 'b0001000;  //   --d-- 
        'hb: seven_segments = 'b0000011;
        'hc: seven_segments = 'b1000110;
        'hd: seven_segments = 'b0100001;
        'he: seven_segments = 'b0000110;
        'hf: seven_segments = 'b0001110;
        endcase

endmodule

//----------------------------------------------------------------------------

// Smiling Snail FSM derived from David Harris & Sarah Harris

module pattern_fsm_moore
(
    input  clock,
    input  reset_n,
    input  a,
    output y
);

    parameter [1:0] S0 = 0, S1 = 1, S2 = 2;

    reg [1:0] state, next_state;

    // state register

    always @ (posedge clock or negedge reset_n)
        if (! reset_n)
            state <= S0;
        else
            state <= next_state;

    // next state logic

    always @*
        case (state)

        S0:
            if (a)
                next_state = S0;
            else
                next_state = S1;

        S1:
            if (a)
                next_state = S2;
            else
                next_state = S1;

        S2:
            if (a)
                next_state = S0;
            else
                next_state = S1;

        default:

            next_state = S0;

        endcase

    // output logic

    assign y = (state == S2);

endmodule

//----------------------------------------------------------------------------

// Smiling Snail FSM derived from David Harris & Sarah Harris

module pattern_fsm_mealy
(
    input  clock,
    input  reset_n,
    input  a,
    output y
);

    parameter S0 = 1'b0, S1 = 1'b1;

    reg state, next_state;

    // state register

    always @ (posedge clock or negedge reset_n)
        if (! reset_n)
            state <= S0;
        else
            state <= next_state;

    // next state logic

    always @*
        case (state)

        S0:
            if (a)
                next_state = S0;
            else
                next_state = S1;

        S1:
            if (a)
                next_state = S0;
            else
                next_state = S1;

        default:

            next_state = S0;

        endcase

    // output logic

    assign y = (a & state == S1);

endmodule

//----------------------------------------------------------------------------

module de0_cv_small
(
    input          CLOCK_50,
    input          RESET_N,

    input   [3:0]  KEY,
    input   [9:0]  SW,

    output  [9:0]  LEDR,

    output  [6:0]  HEX0,
    output  [6:0]  HEX1,
    output  [6:0]  HEX2,
    output  [6:0]  HEX3,
    output  [6:0]  HEX4,
    output  [6:0]  HEX5
);

    wire clock_before_global, clock, shift_out, fsm_out;

    clock_divider_50_MHz_to_1_49_Hz clock_divider_50_MHz_to_1_49_Hz
    (
        .clock_50_MHz  ( CLOCK_50            ),
        .reset_n       ( RESET_N             ),
        .clock_1_49_Hz ( clock_before_global )
    );

    global global
    (
        .in  ( clock_before_global ),
        .out ( clock               )
    );

    //------------------------------------------------------------------------

    wire [15:0] count;

    counter_with_load counter_with_load
    (
        .clock      (   clock        ),
        .reset_n    (   RESET_N      ),

        .load       ( ~ KEY [2]      ),
        .load_data  (   { 6'b0, SW } ),
        .count      (   count        )
    );

    //------------------------------------------------------------------------

    single_digit_display digit_0
    (
        .digit          ( count [ 3: 0] ),
        .seven_segments ( HEX0          )
    );

    single_digit_display digit_1
    (
        .digit          ( count [ 7: 4] ),
        .seven_segments ( HEX1          )
    );

    single_digit_display digit_2
    (
        .digit          ( count [11: 8] ),
        .seven_segments ( HEX2          )
    );

    single_digit_display digit_3
    (
        .digit          ( count [15:12] ),
        .seven_segments ( HEX3          )
    );

    //------------------------------------------------------------------------

    shift_register_with_enable shift_register_with_enable
    (
        .clock   (   clock     ),
        .reset_n (   RESET_N   ),
        .in      ( ~ KEY [1]   ),
        .enable  (   KEY [0]   ),
        .out     (   shift_out ),
        .data    (   LEDR      )
    );           

    //------------------------------------------------------------------------

    wire moore_fsm_out, mealy_fsm_out;

    pattern_fsm_moore pattern_fsm_moore
    (
        .clock   ( clock         ),
        .reset_n ( RESET_N       ),
        .a       ( shift_out     ),
        .y       ( moore_fsm_out )
    );

    pattern_fsm_mealy pattern_fsm_mealy
    (
        .clock   ( clock         ),
        .reset_n ( RESET_N       ),
        .a       ( shift_out     ),
        .y       ( mealy_fsm_out )
    );

    assign HEX5 = moore_fsm_out ? 7'b1100011 : 7'b1111111;
    assign HEX4 = mealy_fsm_out ? 7'b1100011 : 7'b1111111;

endmodule

FSM code is from textbook Digital Design and Computer Architecture, Second Edition by David Harris and Sarah Harris, 2012. Rest of the exercise is created by Yuri Panchul