Published on: January 19, 2014
If you haven’t installed Migen or don’t know about Migen, read my previous blog post Installing Migen – the Python based hardware description language
A D flip-flop spits the data out which is kept in the data input pin when the clock is applied(in positive edge or negative edge). The D flip-flop that we are going to design has the input pin D, output pins Q and Qi(inverted of Q). It also has a clock clock input and a reset pin which makes the flip-flop synchronous.
The D flip-flop shown over here is a positive edge triggered flip-flop. The truth table represents the mapping between the input pins to the output pins based on the reset pin and clock pin state. Since its a positive edge triggered flip-flop, the clock pin is shown as a transition from low to high.
Just for a reference, this is the datasheet of a D flip-flop IC.
Create a file named Dff.py and add this code to it.
from migen.fhdl.std import * class Dflipflop(Module): def __init__(self, D, Q, Qi): self.sync += Q.eq(D) self.comb += Qi.eq(~Q)
Digital circuits can be divided into synchronous(i.e works based on the clock input) and asynchronous(independent of clock) circuits. Asynchronous circuits are also known as combinational logic. The Python syntax used for describing the D flip-flop can be more clearly understood by reading the Migen user guide. So I won’t be explaining here the syntax used. Only describing the synchronous and combinational(asynchronous) statements are in my scope.
self.sync += Q.eq(D)
Q.eq(D) equates/copies the content of D to Q which are the input and output of our flip-flop. This is then assigned as a synchronous using self.sync +=. As mentioned before, a D flip-flop copies the data from the input pin to the output pin in synchronous to the clock transition. Hence this circuit is a synchronous circuit.
self.comb += Qi.eq(~Q)
Qi.eq(~Q) is used to invert Q and copy to Qi. This is assigned as a combinational logic. This means Qi is independent of the clock. But out flip-flop is a synchronous. This doesn’t means that Qi will change asynchronously since the input of Qi is from a synchronous logic Q.
Update your Dff.py with the below code.
from migen.fhdl.std import * from migen.fhdl import verilog from migen.sim.generic import Simulator, TopLevel from random import randrange class Dflipflop(Module): def __init__(self, D, Q, Qi): self.sync += Q.eq(D) self.comb += Qi.eq(~Q) def do_simulation(self,s): s.wr(D,randrange(2)) #Simulation and verilog conversion D = Signal() Q = Signal() Qi = Signal() #print(verilog.convert(Dflipflop(D, Q, Qi), ios={D,Q,Qi})) sim = Simulator(Dflipflop(D,Q,Qi), TopLevel("Dff.vcd")) sim.run(100)
Execute this python script using the below command. This will generate a Dff.vcd which contains the test result. The vcd file can be viewed using GTKWave tool.
python3 Dff.py
gtkwave Dff.vcd
As I mentioned before, read the official Migen user guide and tutorial to understand what the code means.
To test the D flip-flop, we need to check if the input (D) is copied to the output(Q and also Qi). For this the input D should be fed with values(0 or 1). We can use the module random in Python to generate some random values.
s.wr(D,randrange(2))
The function randrange(2) generates a random number – either 0 or 1. s.wr writes the random number to D. The write happens only after the positive edge of the clock cycle.
As I mentioned in my previous blog post (Installing Migen – the Python based hardware description language), Migen converts the Python code to equivalent Verilog code. Since the FPGA tools which we currently have only understands only Verilog/VHDL, this is required. The generated Verilog code can be loaded to your FPGA vendor’s software and verified on real hardware. Mibuild(a tool inside Migen) supports few FPGA vendors for which you don’t have to manually paste your Verilog code to the FPGA vendor’s software. Mibuild will do it for you(by accessing vendor tools via command line) and even it can load the bit stream file to FPGA. Usage of Mibuild will be explained later.
Uncomment the line in your Dff.py file and run the python code again. This line will print the Verilog equivalent code of our D flip-flop.
print(verilog.convert(Dflipflop(D, Q, Qi), ios={D,Q,Qi}))
Below is the Verilog output.
/* Machine-generated using Migen */ module top( input D, output reg Q, output Qi, input sys_clk, input sys_rst ); // synthesis translate_off reg dummy_s; initial dummy_s <= 1'd0; // synthesis translate_on assign Qi = (~Q); always @(posedge sys_clk) begin if (sys_rst) begin Q <= 1'd0; end else begin Q <= D; end end endmodule
Note: Below shown is not the right way to do a frequency division. This is just an example to show Migen’s testing capabilities.
A D filp-flop can be used as a frequency divider (frequency / 2). Read this for a more clear explanation. Make a connection from Qi to D to divide the frequency(fed to the clock pin) by 2. Connecting a wire between pins is very easy in Migen - just use the same Signal() for both the pins.
Create a file named Dff_Divider.py and add the below code.
from migen.fhdl.std import * from migen.fhdl import verilog from migen.sim.generic import Simulator, TopLevel class Dflipflop(Module): def __init__(self, D, Q, Qi): self.sync += Q.eq(D) self.comb += Qi.eq(~Q) #Simulation and verilog conversion part Connect = Signal() Q = Signal() sim = Simulator(Dflipflop(Connect,Q,Connect), TopLevel("Dff_Divider.vcd")) sim.run(100)
Comments can be emailed or tweeted to me. I would like to hear them and will try to reply.
Made using Jekyll, Twitter Bootstrap, Code Prettify and Font Awesome.
Copyright (C) 2008 - 2021 Jeffrey.