DFF and TFF (Toggle Flip-Flop)

In this example we create a toggle flip-flop (TFF) from a d-flip-flop (DFF). In Magma, finite state machines can be constructed by composing combinational logic with flop-flops register primitives.


In [1]:
import magma as m
from mantle import DFF

In [2]:
class TFF(m.Circuit):
    io = m.IO(O=m.Out(m.Bit)) + m.ClockIO()
    # instance a dff to hold the state of the toggle flip-flop - this needs to be done first
    dff = DFF()
    # compute the next state as the not of the old state ff.O
    io.O <= dff(~dff.O)
        
def tff():
    return TFF()()

Test using the python simulator.


In [3]:
from fault import PythonTester
tester = PythonTester(TFF, TFF.CLK)

tester.eval()
val = tester.peek(TFF.O)
assert val == False

for i in range(10):
    val = not val
    
    tester.step() # toggle clock - now High
    assert val == tester.peek(TFF.O)

    tester.step() # toggle clock - now Low
    assert val == tester.peek(TFF.O)

print("Success!")


Success!

Generate Verilog

Generate verilog with coreir.


In [4]:
m.compile("build/TFF", TFF, inline=True)
%cat build/TFF.v


module coreir_reg #(
    parameter width = 1,
    parameter clk_posedge = 1,
    parameter init = 1
) (
    input clk,
    input [width-1:0] in,
    output [width-1:0] out
);
  reg [width-1:0] outReg=init;
  wire real_clk;
  assign real_clk = clk_posedge ? clk : ~clk;
  always @(posedge real_clk) begin
    outReg <= in;
  end
  assign out = outReg;
endmodule

module DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse (
    input I,
    output O,
    input CLK
);
wire [0:0] reg_P_inst0_out;
coreir_reg #(
    .clk_posedge(1'b1),
    .init(1'h0),
    .width(1)
) reg_P_inst0 (
    .clk(CLK),
    .in(I),
    .out(reg_P_inst0_out)
);
assign O = reg_P_inst0_out[0];
endmodule

module TFF (
    output O,
    input CLK
);
DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0 (
    .I(~ O),
    .O(O),
    .CLK(CLK)
);
endmodule


In [5]:
%cat build/TFF.json


{"top":"global.TFF",
"namespaces":{
  "global":{
    "modules":{
      "DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse":{
        "type":["Record",[
          ["I","BitIn"],
          ["O","Bit"],
          ["CLK",["Named","coreir.clkIn"]]
        ]],
        "instances":{
          "reg_P_inst0":{
            "genref":"coreir.reg",
            "genargs":{"width":["Int",1]},
            "modargs":{"clk_posedge":["Bool",true], "init":[["BitVector",1],"1'h0"]}
          }
        },
        "connections":[
          ["self.CLK","reg_P_inst0.clk"],
          ["self.I","reg_P_inst0.in.0"],
          ["self.O","reg_P_inst0.out.0"]
        ]
      },
      "TFF":{
        "type":["Record",[
          ["O","Bit"],
          ["CLK",["Named","coreir.clkIn"]]
        ]],
        "instances":{
          "DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0":{
            "modref":"global.DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse"
          },
          "magma_Bit_not_inst0":{
            "modref":"corebit.not"
          }
        },
        "connections":[
          ["self.CLK","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.CLK"],
          ["magma_Bit_not_inst0.out","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.I"],
          ["magma_Bit_not_inst0.in","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.O"],
          ["self.O","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.O"]
        ]
      }
    }
  }
}
}

In [6]:
!coreir -i build/TFF.json -p instancecount


An instance count of all the primitives
=======================================
DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse | instances in current | instances in children | 
  coreir_reg__width1 | 1 | 0

TFF | instances in current | instances in children | 
  corebit_not | 1 | 0
  coreir_reg__width1 | 0 | 1

=======================================
{"top":"global.TFF",
"namespaces":{
  "global":{
    "modules":{
      "DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse":{
        "type":["Record",[
          ["I","BitIn"],
          ["O","Bit"],
          ["CLK",["Named","coreir.clkIn"]]
        ]],
        "instances":{
          "reg_P_inst0":{
            "genref":"coreir.reg",
            "genargs":{"width":["Int",1]},
            "modargs":{"clk_posedge":["Bool",true], "init":[["BitVector",1],"1'h0"]}
          }
        },
        "connections":[
          ["self.CLK","reg_P_inst0.clk"],
          ["self.I","reg_P_inst0.in.0"],
          ["self.O","reg_P_inst0.out.0"]
        ]
      },
      "TFF":{
        "type":["Record",[
          ["O","Bit"],
          ["CLK",["Named","coreir.clkIn"]]
        ]],
        "instances":{
          "DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0":{
            "modref":"global.DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse"
          },
          "magma_Bit_not_inst0":{
            "modref":"corebit.not"
          }
        },
        "connections":[
          ["self.CLK","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.CLK"],
          ["magma_Bit_not_inst0.out","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.I"],
          ["magma_Bit_not_inst0.in","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.O"],
          ["self.O","DFF_init0_has_ceFalse_has_resetFalse_has_async_resetFalse_inst0.O"]
        ]
      }
    }
  }
}
}
/Users/travis/build/leonardt/pycoreir/coreir-cpp/src/binary/coreir.cpp:238 Modified?: No

Here's an example of testing using fault's staged Tester class and the verilator simulator.


In [7]:
import fault
tester = fault.Tester(TFF, TFF.CLK)
for i in range(5):
    tester.step(2)
    tester.print("TFF.O=%d\n", TFF.O)
tester.compile_and_run("verilator", disp_type='realtime')


Running command: verilator -Wall -Wno-INCABSPATH -Wno-DECLFILENAME --cc TFF.v --exe TFF_driver.cpp --top-module TFF
Running command: verilator --version
<STDOUT>
Verilator 4.013 devel rev UNKNOWN_REV
</STDOUT>
Running command: make -C obj_dir -j -f VTFF.mk VTFF
<STDOUT>
clang++  -I.  -MMD -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -faligned-new -fbracket-depth=4096 -Qunused-arguments -Wno-parentheses-equality -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter -Wno-unused-variable -Wno-shadow       -c -o TFF_driver.o ../TFF_driver.cpp
/usr/bin/perl /usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include VTFF.cpp > VTFF__ALLcls.cpp
/usr/bin/perl /usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include VTFF__Syms.cpp > VTFF__ALLsup.cpp
clang++  -I.  -MMD -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -faligned-new -fbracket-depth=4096 -Qunused-arguments -Wno-parentheses-equality -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter -Wno-unused-variable -Wno-shadow       -c -o VTFF__ALLcls.o VTFF__ALLcls.cpp
clang++  -I.  -MMD -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include -I/usr/local/Cellar/verilator/HEAD-efa6f4c/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -faligned-new -fbracket-depth=4096 -Qunused-arguments -Wno-parentheses-equality -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter -Wno-unused-variable -Wno-shadow       -c -o VTFF__ALLsup.o VTFF__ALLsup.cpp
      Archiving VTFF__ALL.a ...
ar r VTFF__ALL.a VTFF__ALLcls.o VTFF__ALLsup.o
ranlib VTFF__ALL.a
clang++    TFF_driver.o verilated.o VTFF__ALL.a    -o VTFF -lm -lstdc++
</STDOUT>
Running command: ./obj_dir/VTFF
<STDOUT>
TFF.O=1
TFF.O=0
TFF.O=1
TFF.O=0
TFF.O=1
</STDOUT>