From Python to silicon
 

Flip-flops and Latches

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.

What you will learn

On this page, you will learn about the following MyHDL features and techniques:

  • modelling and simulating small sequential devices
  • waveform viewing
  • automatic conversion to Verilog

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 *
 
def dff(q, d, clk):
 
    @always(clk.posedge)
    def logic():
        q.next = d
 
    return logic

Simulation

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

from random import randrange
 
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):
    tb = traceSignals(test_dff)
    sim = Simulation(tb)
    sim.run(timesteps)
 
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.jpg

Automatic conversion to Verilog

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

def convert():
    q, d, clk = [Signal(bool(0)) for i in range(3)]
    toVerilog(dff, q, d, clk)
 
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 *
 
def dffa(q, d, clk, rst):
 
    @always(clk.posedge, rst.negedge)
    def logic():
        if rst == 0:
            q.next = 0
        else:
            q.next = d
 
    return logic

Simulation

Here is a test bench for the design:

from random import randrange
 
def test_dffa():
 
    q, d, clk, rst = [Signal(bool(0)) for i in range(4)]
 
    dffa_inst = 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):
    tb = traceSignals(test_dffa)
    sim = Simulation(tb)
    sim.run(timesteps)
 
simulate(20000)

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.jpg

Automatic conversion to Verilog

The design can be converted to Verilog as follows:

def convert():
    q, d, clk, rst = [Signal(bool(0)) for i in range(4)]
    toVerilog(dffa, q, d, clk, rst)
 
convert()

The result looks like this:

module dffa (
    q,
    d,
    clk,
    rst
);
 
output q;
reg q;
input d;
input clk;
input rst;
 
 
always @(posedge clk or negedge rst) begin: _dffa_logic
    if ((rst == 0)) begin
        q <= 0;
    end
    else begin
        q <= d;
    end
end
 
endmodule

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 *
 
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
 
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):
    tb = traceSignals(test_latch)
    sim = Simulation(tb)
    sim.run(timesteps)
 
simulate(20000)

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.jpg

Automatic conversion to Verilog

We can convert the design as follows:

def convert():
    q, d, g = [Signal(bool(0)) for i in range(3)]
    toVerilog(latch, q, d, g)
 
convert()

Here is the result:

module latch (
    q,
    d,
    g
);
 
output q;
reg q;
input d;
input g;
 
always @(d, g) begin: _latch_logic
    if ((g == 1)) begin
        q <= d;
    end
end
 
endmodule

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

cookbook/ff.txt · Last modified: 2011/05/25 21:35 by jandecaluwe
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki