Introduction

On this page you will find a number of MyHDL descriptions of flip-flops and latches.

Typically, you wouldn't describe flip-flops and latches as individual modules. Rather, they can be inferred from higher-level RTL description by a synthesis tool. However, as these circuits are small and widely known, they are well suited to explain basic MyHDL usage and to compare MyHDL with other solutions.

D flip-flop

Specification

The basic D flip-flop is a sequential device that transfers the value of the d input to the q output on every rising edge of the clock clk.

Description

Here is the description of a D flip-flop in MyHDL:

from myhdl import *

@block
def dff(q, d, clk):

    @always(clk.posedge)
    def logic():
        q.next = d

    return logic

Simulation

Let's add a small test bench to simulate the design:

from random import randrange

@block
def test_dff():

    q, d, clk = [Signal(bool(0)) for i in range(3)]

    dff_inst = dff(q, d, clk)

    @always(delay(10))
    def clkgen():
        clk.next = not clk

    @always(clk.negedge)
    def stimulus():
        d.next = randrange(2)

    return dff_inst, clkgen, stimulus


def simulate(timesteps):
    simInst = test_dff() 
    simInst.config_sim(trace=True, tracebackup=False)
    simInst.run_sim(timesteps, quiet=0) 

simulate(2000)

Function test_dff creates an instance of the D flip-flop, and adds a clock generator and a random stimulus generator around it.

Function simulate simulates the test bench. Note how the MyHDL function traceSignals is used to create the test bench instance (instead of calling test_dff directly). As a result, a signal trace file will be created during simulation. This file can be inspecting in a waveform viewer. As a verification method, inspecting waveforms has its drawbacks, but it can be very effective to debug small designs.

Here's a screen shot of the simulation waveforms:

test_dff waveforms

Automatic conversion to Verilog or VHDL

With MyHDL's convert function, a D flip-flop instance can be converted to Verilog or VHDL code:

def convert():
    q, d, clk = [Signal(bool(0)) for i in range(3)]
    convInst = dff(q, d, clk)  #, 'Verilog')  
    convInst.convert(hdl='Verilog')
    convInst.convert(hdl='VHDL')

convert()

This is the resulting Verilog code:

module dff (
    q,
    d,
    clk
);

output q;
reg q;
input d;
input clk;

always @(posedge clk) begin: DFF_LOGIC
    q <= d;
end

endmodule

D flip-flop with asynchronous reset

Specification

One of the most useful sequential building blocks is a D flip-flop with an additional asynchronous reset pin. When the reset is not active, it operates as a basic D flip-flop as in the previous section. When the reset pin is active, the output is held to zero. Typically, the reset pin is active low.

Description

Here is the description:

from myhdl import *

@block
def dffa(q, d, clk, rst):

    @always_seq(clk.posedge, reset=rst)
    def logic():
        if rst == 0:    # nRst ?  or use active high ?
            q.next = 0
        else:
            q.next = d

    return logic

Simulation

Here is a test bench for the design:

from random import randrange

@block
def test_dffa():

    q, d, clk = [Signal(bool(0)) for i in range(3)]
    rst = ResetSignal(val=1, active=0, isasync=True)

    dffa_inst01 = dffa(q, d, clk, rst)

    @always(delay(10))
    def clkgen():
        clk.next = not clk

    @always(clk.negedge)
    def stimulus():
        d.next = randrange(2)

    @instance
    def rstgen():
        yield delay(5)
        rst.next = 1
        while True:
            yield delay(randrange(500, 1000))
            rst.next = 0
            yield delay(randrange(80, 140))
            rst.next = 1

    return dffa_inst, clkgen, stimulus, rstgen


def simulate(timesteps):
    simInst = test_dffa() 
    simInst.config_sim(trace=True, tracebackup=False)
    simInst.run_sim(timesteps, quiet=0) 

simulate(2000)

Compared to the test bench for the basic D flip-flop, there is an additional reset generator, that generates reset pulses at random moments and with a random duration.

Here is a screen shot of the waveforms:

test_dffa waveforms

Automatic conversion to Verilog or VHDL

The design can be converted to Verilog and VHDL:

def convert():
    q, d, clk = [Signal(bool(0)) for i in range(3)]
    rst = ResetSignal(val=1, active=0, isasync=True)
    convInst = dffa(q, d, clk, rst)
    convInst.convert(hdl='Verilog')
    convInst.convert(hdl='VHDL')

convert()

The VHDL result looks like this:

entity dffa is
    port (
        q: out std_logic;
        d: in std_logic;
        clk: in std_logic;
        rst: in std_logic
    );
end entity dffa;

architecture MyHDL of dffa is
begin
DFFA_LOGIC: process (clk, rst) is
begin
    if (rst = '0') then
        q <= '0';
    elsif rising_edge(clk) then
        if (rst = '0') then
            q <= '0';
        else
            q <= d;
        end if;
    end if;
end process DFFA_LOGIC;

end architecture MyHDL;

Latch

Specification

A basic latch is a sequential device with an input, and output and a control gate pin. When the gate is open, the output follows the input combinatorially. When it is closed, the output keeps its value.

Description

The following code describes a latch:

from myhdl import *

@block 
def latch(q, d, g):

    @always_comb
    def logic():
        if g == 1:
            q.next = d

    return logic

Note the usage of the always_comb decorator. This is somewhat of a misnomer. (The name comes from a similar construct in SystemVerilog). It doesn't mean the generator describes a circuit that is necessarily combinatorial, but merely that it triggers whenever one of the input signals changes.

Simulation

Here is a test bench to simulate the latch:

from random import randrange

@block 
def test_latch():

    q, d, g = [Signal(bool(0)) for i in range(3)]

    latch_inst = latch(q, d, g) 

    @always(delay(7))
    def dgen():
        d.next = randrange(2)

    @always(delay(41))
    def ggen():
        g.next = randrange(2)


    return latch_inst, dgen, ggen

def simulate(timesteps):
    simInst = test_latch() 
    simInst.config_sim(trace=True)
    simInst.run_sim(timesteps, quiet=0) 

simulate(2000)

In addition to the latch instance, the test bench creates a random data generator for the input and for the controlling gate.

Here is a screen shot of the simulation waveforms:

test_latch waveforms

Automatic conversion to Verilog or VHDL

We can convert the design as follows:

def convert():
    q, d, g = [Signal(bool(0)) for i in range(3)]
    convInst = latch(q, d, g)
    convInst.convert(hdl='Verilog')
    convInst.convert(hdl='VHDL')

convert()

Here is the verilog result:

module latch (
    q,
    d,
    g
);

output q;
reg q;
input d;
input g;

always @(g, d) begin: LATCH_LOGIC
    if ((g == 1)) begin
        q = d;
    end
end

endmodule

Note that when the convert function converts the always_comb decorator, it infers which signals are used as inputs to the always block