File size: 2,831 Bytes
e9bc512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
"""

Hyperrealistic voltage-based flip-flops: SR, D, JK, and T.

Each flip-flop is built from voltage-based logic gates and simulates real-world behavior.

"""
from logic_gates import NANDGate, ANDGate, ORGate, NOTGate, VDD, VSS, VTH, GATE_DELAY
import time

class SRFlipFlop:
    """Set-Reset flip-flop using cross-coupled NAND gates."""
    def __init__(self):
        self.nand1 = NANDGate()
        self.nand2 = NANDGate()
        self.q = VSS
        self.q_bar = VDD

    def update(self, s, r):
        # s, r are voltages
        # Cross-coupled NANDs
        q_new = self.nand1.output(s, self.q_bar)
        q_bar_new = self.nand2.output(r, q_new)
        self.q = q_new
        self.q_bar = q_bar_new
        return self.q, self.q_bar

class DFlipFlop:
    """D (Data) flip-flop using SR flip-flop and NOT gate."""
    def __init__(self):
        self.sr = SRFlipFlop()
        self.notg = NOTGate()

    def update(self, d, clk):
        # d, clk are voltages
        s = self.nand(d, clk)
        r = self.nand(self.notg.output(d), clk)
        return self.sr.update(s, r)

    def nand(self, a, b):
        return NANDGate().output(a, b)

class JKFlipFlop:
    """JK flip-flop using NAND gates."""
    def __init__(self):
        self.q = VSS
        self.q_bar = VDD
        self.nand1 = NANDGate()
        self.nand2 = NANDGate()
        self.nand3 = NANDGate()
        self.nand4 = NANDGate()

    def update(self, j, k, clk):
        # j, k, clk are voltages
        j_in = self.nand1.output(j, clk, self.q_bar)
        k_in = self.nand2.output(k, clk, self.q)
        q_new = self.nand3.output(j_in, self.q_bar)
        q_bar_new = self.nand4.output(k_in, q_new)
        self.q = q_new
        self.q_bar = q_bar_new
        return self.q, self.q_bar

class TFlipFlop:
    """T (Toggle) flip-flop using JK flip-flop."""
    def __init__(self):
        self.jk = JKFlipFlop()

    def update(self, t, clk):
        # t, clk are voltages
        return self.jk.update(t, t, clk)

# Example usage
if __name__ == "__main__":
    print("SR Flip-Flop:")
    sr = SRFlipFlop()
    print("Set:", sr.update(VDD, VSS))
    print("Reset:", sr.update(VSS, VDD))
    print("Hold:", sr.update(VSS, VSS))

    print("\nD Flip-Flop:")
    dff = DFlipFlop()
    print("D=1, CLK=1:", dff.update(VDD, VDD))
    print("D=0, CLK=1:", dff.update(VSS, VDD))

    print("\nJK Flip-Flop:")
    jk = JKFlipFlop()
    print("J=1, K=0, CLK=1:", jk.update(VDD, VSS, VDD))
    print("J=0, K=1, CLK=1:", jk.update(VSS, VDD, VDD))
    print("J=1, K=1, CLK=1 (toggle):", jk.update(VDD, VDD, VDD))

    print("\nT Flip-Flop:")
    tff = TFlipFlop()
    print("T=1, CLK=1 (toggle):", tff.update(VDD, VDD))
    print("T=0, CLK=1 (hold):", tff.update(VSS, VDD))