Applications 10

De la WikiLabs


Design, verify and implement a triangular sequence generator. It generates a sequence of numbers that periodically increase and decrease between two configurable limits, limith and limitl. The sequence rate is one number per second. The binary sequence of numbers, bcd, is outputted for display as seg_bcd. Figure 1 shows an example of triangular sequence that varies between 6 and 9. The bottom waveform is the analog signal that would be generated by a DAC whose input is the bcd sequence.

Figure 1

Appl10 triangle wave.png

The default limit values are 0 for limitl and 9 for limith, and they are set each time the reset is applied. To change the limits use the push button in this order. Set din to a desired value for the low limit and push the push button to set the limitl value to din value. Then change the din value to the desired high limit and with a second push set the limith value this new din value. The current din value is displayed through seg_din output. After configuration is done, the push button is ignored.



The top level design, named triangle, has 4 sequential blocks and one dual port ROM memory (Figure 2).

Figure 2

Appl10 triangle.png

All sequential blocks are clocked by the same 50 MHz input clock and share the reset sinal, rst, active 0.


To easy the design of the circuit, the pulse generator, pulsegen, generates a periodic sequence of pulses, at a rate of one pulse per second, each pulse lasting only one clock cycle. The pulsegen is a counter that generates one pulse at each 50,000,000 clock cycles. However, to make possible the verification of the circuit, this number is not given as an explicit literal in HDL description but as a parameter declared inside the pulsegen module:

parameter CYCLE = 50000000;

The parameter value may be changed from the testbench to much lower values, suitable for verification (otherwise the simulation will run for hours to count 50 million pulses!).

The pulsegen output, pulse, is used to enable the counting of the cnt_bcd counter.


Whenever its cen input is active, it increments or decrements, according to dir input. If dir is 0 it increments. If dir is 1 it decrements.


This automaton controls the sequence generated by cnt_bcd, changing its direction of counting such that to keep the bcd sequence between the limits, limitl and limith. Whenever bcd value reaches one of the limits, the counting direction, dir, is reversed.


Another automaton controls the configuration process. It keeps two registers, limith and limitl, whose values are changed according to the configuration protocol described above. At the reset, their values are set to the default ones, 9 and 0. Two successive push update the values of the limits, after which the new limit values stay stable until reset. Keep in mind that the push button is active 0, and that a push is completed after the button is released.


The ROM memory is a dual port read only memory. It may be initialized through the $readmemh or $readmemb tasks with proper values for digit display. Alternatively, the initialization of the memory content may be done with an init process:

initial begin // the last 7 bits are the digit segment values
    mem[0] = 8'b01000000;
    mem[1] = 8'b01111001;
    .... // initialization for the other memory locations


Write a testbench with the following test scenario:

  • apply reset
  • wait for 100 clock cycles
  • set din and apply push for a couple of cycles
  • change din to a high limit and apply push for a couple of cycles
  • let the simulation run for some other 100 clock cycles

In the testbench module redefine the pulsegen parameter, such that is generates a pulse at each 5 clock cycles (instead of one at each 50,000,000 cycles):

defparam dut.pulsegen.CYCLE = 5;


Using the recommended board display digits, push buttons, switches and clock sources (see Figure 1), implement the triangle top-level design module.


pulsegen(rst, clk, pulse) with an internal parameter named CYCLE

cnt_bcd(rst, clk, cen, dir, value)

fsm_cnt(rst, clk, limith, limitl, value, dir)

fsm_ctrl(rst, clk, push, din, limith, limitl)

rom16x8(addra, douta, addrb, doutb)

triangle(rst, clk, push, din, seg_din, seg_bcd) with the pulsegen instance name pulsegen and a 4 bit connection named bcd

triangle_tb with the triangle instance name dut