5. More Design examples

5.1. Introduction

Note

In this chapter, some more useful designs are implemented which can be used to build the large systems. Here, we will re-implement the designs of the Chapter “Design examples” in the Verilog/VHDL tutorial. Please see the Verilog/SystemVerilog/VHDL tutorials for the explanation of the designs.

5.2. Linear Feedback Shift Register (LFSR)

  • In the below code, LFSR is implemented which is used to generate the pseudo random numbers. Further, the generated random number is displayed on seven-segment display device and LEDs.

    Note

    In the below code, the generated random number will be displayed on the seven-segment display device and LEDs. Since, the seven segment display device can show the number upto ‘F’ only, therefore the code will work for N = 3 only. While increasing the value of N, please comment the HEX0 connection from the Python 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
    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
    # rand_num_gen.py
    # result is same as 'rand_num_generator.v' in the Verilog tutorial
    
    from myhdl import *
    
    # from mod_m_counter import mod_m_counter
    from clock_tick import clock_tick
    from hex_to_seven_seg import hex_to_seven_seg
    
    @block
    def rand_num_gen(clk, reset_n, q):
        N = 3
        # change the value of feedback_value in feedback_logic according to
        # the value of N
        r_reg = Signal(intbv(0)[N+1:0])
        r_next = Signal(intbv(0)[N+1:0])
    
        feedback_value = Signal(bool(0))
    
        @always(clk.posedge, reset_n.negedge)
        def current_state_logic():
            if reset_n == 0 :
                r_reg.next = 1
            else :
                r_reg.next = r_next
    
        @always_comb
        def feedback_logic():
            # uncomment correct line based on the value of N
    
            feedback_value.next = r_reg[3] ^ r_reg[2] ^ r_reg[0] # N = 3
            # feedback_value.next = r_reg[4] ^ r_reg[3] ^ r_reg[0] # N = 4
            # feedback_value.next = r_reg[5] ^ r_reg[3] ^ r_reg[0] # N = 5
            # feedback_value.next = r_reg[9] ^ r_reg[5] ^ r_reg[0] # N = 9
    
        @always_comb
        def next_state_logic(): #
            r_next.next = concat(feedback_value, r_reg[N+1:1])
    
            # # use above or uncomment below two lines
            # r_next[N].next = feedback_value
            # r_next[N:0].next = r_reg[N+1:1]
    
    
        @always_comb
        def assign_output():
            q.next = r_reg
    
        return current_state_logic, feedback_logic, \
            assign_output, next_state_logic
    
    @block
    def rand_num_gen_top(CLOCK_50, reset_n, LEDG, HEX0):
        clk_pulse = Signal(bool(0))
        count = Signal(intbv(0)[4:0])
    
        # reduced clock rate
        clock_tick_inst = clock_tick(CLOCK_50, reset_n,
                clk_pulse, 50000000, 29)
    
        # rand_num_gen with new port names
        rand_num_gen_verilog = rand_num_gen(clk=clk_pulse,
                reset_n=reset_n, q=count)
    
        # below will not work for N > 3 as seven-segment can display upto F
        hex_to_seven_seg_test_inst = hex_to_seven_seg(count, HEX0)
    
        # send count to LEDG
        @always_comb
        def led_logic():
            LEDG.next = count
    
        return rand_num_gen_verilog, clock_tick_inst, \
                    hex_to_seven_seg_test_inst, led_logic
    
    
    def main():
        N = 3  # set the value of same as rand_num_gen
        clk = Signal(bool(0))
        reset_n = Signal(bool(0))
        q = Signal(intbv(0)[N+1:0])
    
        # HEX0 will work for N = 3 only, as seven segment can display till F only
        HEX0 = Signal(intbv(0)[7:0])
    
        # rand_num_gen for simulation
        rand_num_gen_verilog = rand_num_gen(clk, reset_n, q)
        rand_num_gen_verilog.convert(hdl="Verilog", initial_values=True)
    
        # rand_num_gen for visual testing
        rand_num_gen_top_verilog = rand_num_gen_top(clk, reset_n, q, HEX0)
        rand_num_gen_top_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__':
        main()
    
  • Following is the resultant Verilog code generate by the instance “rand_num_gen_top_verilog” in above listing. Load this design on the FPGA board; and the generated random numbers will be displayed on the seven-segment display device.

      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
    137
    138
    139
    140
    141
    142
    // File: rand_num_gen_top.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:57:19 2017
    
    
    `timescale 1ns/10ps
    
    module rand_num_gen_top (
        CLOCK_50,
        reset_n,
        LEDG,
        HEX0
    );
    
    
    input CLOCK_50;
    input reset_n;
    output [3:0] LEDG;
    wire [3:0] LEDG;
    output [6:0] HEX0;
    reg [6:0] HEX0;
    
    reg clk_pulse = 0;
    wire [3:0] count;
    reg [3:0] rand_num_gen_1_r_reg = 0;
    wire [3:0] rand_num_gen_1_r_next;
    wire rand_num_gen_1_feedback_value;
    reg [28:0] clock_tick_1_mod_m_counter_1_count_reg = 0;
    reg [28:0] clock_tick_1_mod_m_counter_1_count_next = 0;
    
    
    
    always @(posedge clk_pulse, negedge reset_n) begin: RAND_NUM_GEN_TOP_RAND_NUM_GEN_1_CURRENT_STATE_LOGIC
        if ((reset_n == 0)) begin
            rand_num_gen_1_r_reg <= 1;
        end
        else begin
            rand_num_gen_1_r_reg <= rand_num_gen_1_r_next;
        end
    end
    
    
    
    assign rand_num_gen_1_feedback_value = ((rand_num_gen_1_r_reg[3] ^ rand_num_gen_1_r_reg[2]) ^ rand_num_gen_1_r_reg[0]);
    
    
    
    assign count = rand_num_gen_1_r_reg;
    
    
    
    assign rand_num_gen_1_r_next = {rand_num_gen_1_feedback_value, rand_num_gen_1_r_reg[(3 + 1)-1:1]};
    
    
    always @(posedge CLOCK_50, negedge reset_n) begin: RAND_NUM_GEN_TOP_CLOCK_TICK_1_MOD_M_COUNTER_1_LOGIC_REG
        if ((reset_n == 0)) begin
            clock_tick_1_mod_m_counter_1_count_reg <= 0;
        end
        else begin
            clock_tick_1_mod_m_counter_1_count_reg <= clock_tick_1_mod_m_counter_1_count_next;
        end
    end
    
    
    always @(clock_tick_1_mod_m_counter_1_count_reg) begin: RAND_NUM_GEN_TOP_CLOCK_TICK_1_MOD_M_COUNTER_1_LOGIC_NEXT
        if (($signed({1'b0, clock_tick_1_mod_m_counter_1_count_reg}) == (50000000 - 1))) begin
            clock_tick_1_mod_m_counter_1_count_next = 0;
        end
        else begin
            clock_tick_1_mod_m_counter_1_count_next = (clock_tick_1_mod_m_counter_1_count_reg + 1);
        end
    end
    
    
    always @(clock_tick_1_mod_m_counter_1_count_reg) begin: RAND_NUM_GEN_TOP_CLOCK_TICK_1_MOD_M_COUNTER_1_COMPLETE_TICK_LOGIC
        if (($signed({1'b0, clock_tick_1_mod_m_counter_1_count_reg}) == (50000000 - 1))) begin
            clk_pulse = 1;
        end
        else begin
            clk_pulse = 0;
        end
    end
    
    
    always @(count) begin: RAND_NUM_GEN_TOP_HEX_TO_SEVEN_SEG_1_LOGIC
        case (count)
            'h0: begin
                HEX0 <= 64;
            end
            'h1: begin
                HEX0 <= 121;
            end
            'h2: begin
                HEX0 <= 36;
            end
            'h3: begin
                HEX0 <= 48;
            end
            'h4: begin
                HEX0 <= 25;
            end
            'h5: begin
                HEX0 <= 18;
            end
            'h6: begin
                HEX0 <= 2;
            end
            'h7: begin
                HEX0 <= 120;
            end
            'h8: begin
                HEX0 <= 0;
            end
            'h9: begin
                HEX0 <= 16;
            end
            'ha: begin
                HEX0 <= 8;
            end
            'hb: begin
                HEX0 <= 3;
            end
            'hc: begin
                HEX0 <= 70;
            end
            'hd: begin
                HEX0 <= 33;
            end
            'he: begin
                HEX0 <= 6;
            end
            default: begin
                HEX0 <= 14;
            end
        endcase
    end
    
    
    
    assign LEDG = count;
    
    endmodule
    

5.3. Random Access Memory (RAM)

In this section, the ‘single port’ and ‘dual port’ RAMs are implemented.

5.3.1. Single port RAM

  • In the below code, a single port RAM is implemented,

     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
    # single_port_ram.py
    # result is same as "single_port_RAM.v" of the Verilog tutorial
    
    from myhdl import *
    
    @block
    def single_port_ram(clk, we, addr, din, dout, addr_width=2, data_width=3) :
        ram_single_port = [Signal(intbv(0)[addr_width:0])
                    for i in range(data_width)]
    
        @always(clk.posedge)
        def write_logic():
            """ write data to address 'addr' """
            if we == 1 :
                ram_single_port[addr].next = din
    
        @always_comb
        def read_logic():
            """ read data from address 'addr' """
            dout.next = ram_single_port[addr]
    
        return read_logic, write_logic
    
    def main():
        addr_width = 3
        data_width = 3
        clk = Signal(bool(0))
        we = Signal(bool(0))
        addr = Signal(intbv(0)[addr_width:0])
        din = Signal(intbv(0)[data_width:0])
        dout = Signal(intbv(0)[data_width:0])
    
        single_port_ram_verilog = single_port_ram(clk, we, addr,
                    din, dout, addr_width, data_width)
    
        single_port_ram_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
    // File: single_port_ram.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 15:59:53 2017
    
    
    `timescale 1ns/10ps
    
    module single_port_ram (
        clk,
        we,
        addr,
        din,
        dout
    );
    
    
    input clk;
    input we;
    input [2:0] addr;
    input [2:0] din;
    output [2:0] dout;
    wire [2:0] dout;
    
    reg [2:0] ram_single_port [0:3-1];
    
    initial begin: INITIALIZE_RAM_SINGLE_PORT
        integer i;
        for(i=0; i<3; i=i+1) begin
            ram_single_port[i] = 0;
        end
    end
    
    
    
    // read data from address 'addr'
    
    assign dout = ram_single_port[addr];
    
    // write data to address 'addr'
    always @(posedge clk) begin: SINGLE_PORT_RAM_WRITE_LOGIC
        if ((we == 1)) begin
            ram_single_port[addr] <= din;
        end
    end
    
    endmodule
    

5.3.2. Dual port RAM

  • Following code implements a dual port RAM,

     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
    # dual_port_ram.py
    # result is same as "dual_port_RAM.v" of the Verilog tutorial
    
    from myhdl import *
    
    @block
    def dual_port_ram(clk, we, addr_rd, addr_wr, din, dout,
            addr_width=2, data_width=3) :
    
        ram_dual_port = [Signal(intbv(0)[addr_width:0])
                    for i in range(data_width)]
    
        @always(clk.posedge)
        def write_logic():
            """ write data to address 'addr' """
            if we == 1 :
                ram_dual_port[addr_wr].next = din
    
        @always_comb
        def read_logic():
            """ read data from address 'addr' """
            dout.next = ram_dual_port[addr_rd]
    
        return read_logic, write_logic
    
    def main():
        addr_width = 3
        data_width = 3
        clk = Signal(bool(0))
        we = Signal(bool(0))
        addr_rd = Signal(intbv(0)[addr_width:0])
        addr_wr = Signal(intbv(0)[addr_width:0])
        din = Signal(intbv(0)[data_width:0])
        dout = Signal(intbv(0)[data_width:0])
    
        dual_port_ram_verilog = dual_port_ram(clk, we, addr_rd,
                addr_wr, din, dout, addr_width, data_width)
    
        dual_port_ram_verilog.convert(hdl="Verilog", initial_values=True)
    if __name__ == '__main__' :
        main()
    
  • Below 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
    // File: dual_port_ram.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 16:02:12 2017
    
    
    `timescale 1ns/10ps
    
    module dual_port_ram (
        clk,
        we,
        addr_rd,
        addr_wr,
        din,
        dout
    );
    
    
    input clk;
    input we;
    input [2:0] addr_rd;
    input [2:0] addr_wr;
    input [2:0] din;
    output [2:0] dout;
    wire [2:0] dout;
    
    reg [2:0] ram_dual_port [0:3-1];
    
    initial begin: INITIALIZE_RAM_DUAL_PORT
        integer i;
        for(i=0; i<3; i=i+1) begin
            ram_dual_port[i] = 0;
        end
    end
    
    
    
    // read data from address 'addr'
    
    assign dout = ram_dual_port[addr_rd];
    
    // write data to address 'addr'
    always @(posedge clk) begin: DUAL_PORT_RAM_WRITE_LOGIC
        if ((we == 1)) begin
            ram_dual_port[addr_wr] <= din;
        end
    end
    
    endmodule
    

5.4. Read only memory (ROM)

  • In the below code, a ROM is implemented which stores the values for the sevent-segment display device. The switches SW provide the address for the ROM and the ROM returns the corresponding pattern for the seven-segment display device.

     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
    # rom_seven_segment.py
    # the result is same as "ROM_seven_segment.v" in Verilog tutorial
    from myhdl import *
    
    @block
    def rom_seven_segment(addr, dout):
        # address width = 4
        # data width = 7
        data = (
                    0b1000000,
                    0b1111001,
                    0b0100100,
                    0b0110000,
                    0b0011001,
                    0b0010010,
                    0b0000010,
                    0b1111000,
                    0b0000000,
                    0b0010000,
                    0b0001000,
                    0b0000011,
                    0b1000110,
                    0b0100001,
                    0b0000110,
                    0b0001110
                )
    
        @always_comb
        def read_logic():
            dout.next = data[int(addr)]
    
        return read_logic
    
    # top level design with updated port names
    @block
    def rom_ss_visual_test(SW, HEX0, LEDG):
        data = Signal(intbv(0)[7:0])
        rom_seven_segment_inst = rom_seven_segment(SW, data)
    
        @always_comb
        def display_logic():
            HEX0.next = data
            LEDG.next = data
    
        return display_logic, rom_seven_segment_inst
    
    # verilog conversion
    def main():
        SW = Signal(intbv(0)[4:0])
        LEDG = Signal(intbv(0)[7:0])
        HEX0 = Signal(intbv(0)[7:0])
    
        rom_seven_segment_verilog = rom_ss_visual_test(SW, HEX0, LEDG)
        rom_seven_segment_verilog.convert(hdl="Verilog", initial_values=True)
    
    if __name__ == '__main__' :
        main()
    
  • The resultant Verilog code is shown below. Load this design to FPGA board and change the switch pattern, and the corresponding HEX value will be shown on seven-segment device.

     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
    // File: rom_ss_visual_test.v
    // Generated by MyHDL 1.0dev
    // Date: Fri Oct 13 16:08:29 2017
    
    
    `timescale 1ns/10ps
    
    module rom_ss_visual_test (
        SW,
        HEX0,
        LEDG
    );
    
    
    input [3:0] SW;
    output [6:0] HEX0;
    wire [6:0] HEX0;
    output [6:0] LEDG;
    wire [6:0] LEDG;
    
    reg [6:0] data = 0;
    
    
    
    
    assign HEX0 = data;
    assign LEDG = data;
    
    
    always @(SW) begin: ROM_SS_VISUAL_TEST_ROM_SEVEN_SEGMENT_1_READ_LOGIC
        case (SW)
            0: data = 64;
            1: data = 121;
            2: data = 36;
            3: data = 48;
            4: data = 25;
            5: data = 18;
            6: data = 2;
            7: data = 120;
            8: data = 0;
            9: data = 16;
            10: data = 8;
            11: data = 3;
            12: data = 70;
            13: data = 33;
            14: data = 6;
            default: data = 14;
        endcase
    end
    
    endmodule