from myhdl import *
from myhdlpeek import Peeker

#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText

"""
Explanation: \title{Phase Lock Loop Components in myHDL}
\author{Steven K Armour}
\maketitle
This notebook is an exploration into the building and testing the Phase Lock Detector and the frequency divider components of an all Digital Phase Lock Loop. Here the Digitial Oscillator and the low pass filter are left for there own exploratory analysis to then allow the reader to design and implement there own PLL.
<h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc" style="margin-top: 1em;"><ul class="toc-item"><li><span><a href="#References" data-toc-modified-id="References-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>References</a></span></li><li><span><a href="#Libraries-used-and-aux-functions" data-toc-modified-id="Libraries-used-and-aux-functions-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Libraries used and aux functions</a></span></li><li><span><a href="#The-Phase-Lock-Loop" data-toc-modified-id="The-Phase-Lock-Loop-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>The Phase Lock Loop</a></span></li><li><span><a href="#Phase-Detectors" data-toc-modified-id="Phase-Detectors-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Phase Detectors</a></span><ul class="toc-item"><li><span><a href="#Negated-XOR" data-toc-modified-id="Negated-XOR-4.1"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Negated XOR</a></span><ul class="toc-item"><li><span><a href="#NXOR_PD-myHDL-implementation" data-toc-modified-id="NXOR_PD-myHDL-implementation-4.1.1"><span class="toc-item-num">4.1.1&nbsp;&nbsp;</span>NXOR_PD myHDL implementation</a></span></li><li><span><a href="#NXOR_PD-myHDL-Testing" data-toc-modified-id="NXOR_PD-myHDL-Testing-4.1.2"><span class="toc-item-num">4.1.2&nbsp;&nbsp;</span>NXOR_PD myHDL Testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-4.1.3"><span class="toc-item-num">4.1.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li><li><span><a href="#Sequntial--Phase-Detector" data-toc-modified-id="Sequntial--Phase-Detector-4.2"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>Sequntial  Phase Detector</a></span><ul class="toc-item"><li><span><a href="#Seq_PD-myHDL-implementation" data-toc-modified-id="Seq_PD-myHDL-implementation-4.2.1"><span class="toc-item-num">4.2.1&nbsp;&nbsp;</span>Seq_PD myHDL implementation</a></span></li><li><span><a href="#Seq_PD-myHDL-testing" data-toc-modified-id="Seq_PD-myHDL-testing-4.2.2"><span class="toc-item-num">4.2.2&nbsp;&nbsp;</span>Seq_PD myHDL testing</a></span><ul class="toc-item"><li><span><a href="#Test-when-$\omega_{\text{REF}}&gt;\omega_{\text{FB}}$" data-toc-modified-id="Test-when-$\omega_{\text{REF}}>\omega_{\text{FB}}$-4.2.2.1"><span class="toc-item-num">4.2.2.1&nbsp;&nbsp;</span>Test when $\omega_{\text{REF}}&gt;\omega_{\text{FB}}$</a></span></li><li><span><a href="#Test-when-$\omega_{\text{REF}}=\omega_{\text{FB}}$" data-toc-modified-id="Test-when-$\omega_{\text{REF}}=\omega_{\text{FB}}$-4.2.2.2"><span class="toc-item-num">4.2.2.2&nbsp;&nbsp;</span>Test when $\omega_{\text{REF}}=\omega_{\text{FB}}$</a></span></li><li><span><a href="#Test-when-$\omega_{\text{REF}}&lt;\omega_{\text{FB}}$" data-toc-modified-id="Test-when-$\omega_{\text{REF}}<\omega_{\text{FB}}$-4.2.2.3"><span class="toc-item-num">4.2.2.3&nbsp;&nbsp;</span>Test when $\omega_{\text{REF}}&lt;\omega_{\text{FB}}$</a></span></li></ul></li><li><span><a href="#Verilog-implementation¶" data-toc-modified-id="Verilog-implementation¶-4.2.3"><span class="toc-item-num">4.2.3&nbsp;&nbsp;</span>Verilog implementation¶</a></span></li></ul></li></ul></li><li><span><a href="#Fractional-Frequency-Dividers" data-toc-modified-id="Fractional-Frequency-Dividers-5"><span class="toc-item-num">5&nbsp;&nbsp;</span>Fractional Frequency Dividers</a></span><ul class="toc-item"><li><span><a href="#Divide-by-2" data-toc-modified-id="Divide-by-2-5.1"><span class="toc-item-num">5.1&nbsp;&nbsp;</span>Divide by 2</a></span><ul class="toc-item"><li><span><a href="#Divide-by-2-myHDL-implementation" data-toc-modified-id="Divide-by-2-myHDL-implementation-5.1.1"><span class="toc-item-num">5.1.1&nbsp;&nbsp;</span>Divide by 2 myHDL implementation</a></span></li><li><span><a href="#Divide-by-2-myHDL-testing" data-toc-modified-id="Divide-by-2-myHDL-testing-5.1.2"><span class="toc-item-num">5.1.2&nbsp;&nbsp;</span>Divide by 2 myHDL testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-5.1.3"><span class="toc-item-num">5.1.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li><li><span><a href="#Divide-by-3" data-toc-modified-id="Divide-by-3-5.2"><span class="toc-item-num">5.2&nbsp;&nbsp;</span>Divide by 3</a></span><ul class="toc-item"><li><span><a href="#Divide-by-3-myHDL-implementation" data-toc-modified-id="Divide-by-3-myHDL-implementation-5.2.1"><span class="toc-item-num">5.2.1&nbsp;&nbsp;</span>Divide by 3 myHDL implementation</a></span></li><li><span><a href="#Divide-by-3-myHDL-testing" data-toc-modified-id="Divide-by-3-myHDL-testing-5.2.2"><span class="toc-item-num">5.2.2&nbsp;&nbsp;</span>Divide by 3 myHDL testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-5.2.3"><span class="toc-item-num">5.2.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li><li><span><a href="#Divide-by-2/3" data-toc-modified-id="Divide-by-2/3-5.3"><span class="toc-item-num">5.3&nbsp;&nbsp;</span>Divide by 2/3</a></span><ul class="toc-item"><li><span><a href="#Divide-by-2/3-myHDL-implementation" data-toc-modified-id="Divide-by-2/3-myHDL-implementation-5.3.1"><span class="toc-item-num">5.3.1&nbsp;&nbsp;</span>Divide by 2/3 myHDL implementation</a></span></li><li><span><a href="#Divide-by-2/3-myHDL-testing" data-toc-modified-id="Divide-by-2/3-myHDL-testing-5.3.2"><span class="toc-item-num">5.3.2&nbsp;&nbsp;</span>Divide by 2/3 myHDL testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-5.3.3"><span class="toc-item-num">5.3.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li><li><span><a href="#Divide-by-4/5" data-toc-modified-id="Divide-by-4/5-5.4"><span class="toc-item-num">5.4&nbsp;&nbsp;</span>Divide by 4/5</a></span><ul class="toc-item"><li><span><a href="#Divide-by-4/5-myHDL-implementation" data-toc-modified-id="Divide-by-4/5-myHDL-implementation-5.4.1"><span class="toc-item-num">5.4.1&nbsp;&nbsp;</span>Divide by 4/5 myHDL implementation</a></span></li><li><span><a href="#Divide-by-4/5-myHDL-testing" data-toc-modified-id="Divide-by-4/5-myHDL-testing-5.4.2"><span class="toc-item-num">5.4.2&nbsp;&nbsp;</span>Divide by 4/5 myHDL testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-5.4.3"><span class="toc-item-num">5.4.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li><li><span><a href="#Divide-by-6-via-cascaded-2-and-3" data-toc-modified-id="Divide-by-6-via-cascaded-2-and-3-5.5"><span class="toc-item-num">5.5&nbsp;&nbsp;</span>Divide by 6 via cascaded 2 and 3</a></span><ul class="toc-item"><li><span><a href="#Divide-by-6-myHDL-implementation" data-toc-modified-id="Divide-by-6-myHDL-implementation-5.5.1"><span class="toc-item-num">5.5.1&nbsp;&nbsp;</span>Divide by 6 myHDL implementation</a></span></li><li><span><a href="#Divide-by-6-myHDL-testing" data-toc-modified-id="Divide-by-6-myHDL-testing-5.5.2"><span class="toc-item-num">5.5.2&nbsp;&nbsp;</span>Divide by 6 myHDL testing</a></span></li><li><span><a href="#Verilog-implementation" data-toc-modified-id="Verilog-implementation-5.5.3"><span class="toc-item-num">5.5.3&nbsp;&nbsp;</span>Verilog implementation</a></span></li></ul></li></ul></li><li><span><a href="#ToDo" data-toc-modified-id="ToDo-6"><span class="toc-item-num">6&nbsp;&nbsp;</span>ToDo</a></span></li></ul></div>

References
@misc{allen_2003,
title={LECTURE 170  APPLICATIONS OF PLLS AND FREQUENCY DIVIDERS (PRESCALERS)},
author={Allen, Phillip E.},
year={2003}
},
@phdthesis{gal_2012,
title={Design of Fractional-N Phase Locked Loops For Frequency Synthesis From 30 To 40 GHz},
school={McGill University},
author={Gal, George},
year={2012}
},
@misc{niknejad_2014,
title={Phase Locked Loops (PLL) and Frequency Synthesis},
author={Niknejad, Ali M.},
year={2014}
},
@book{razavi_2009,
place={Upper Saddle River, NJ},
edition={1},
title={RF microelectronics},
publisher={Prentice Hall},
author={Razavi, Behzad},
year={2009},
pages={Chapter 8}
}
@book{craninckx_steyaert_1998,
place={New York},
title={Wireless CMOS frequency synthesizer design},
publisher={Springer},
author={Craninckx, J and Steyaert, M},
year={1998}
pages={42-46}
}
Libraries used and aux functions
End of explanation
"""


@block
def NXORPD(clkREF, clkFB, LOCK):
    """
    Negated XOR Phase Detector
    I/O:
        clkREF (bool; in): Ref clock
        clkFB (bool; in): Compere clock
        LOCK (bool; out): Negated XOR (LOCK) result
    
    """
    @always_comb
    def logic():
        LOCK.next= not (clkREF^clkFB)
    
    return instances()

"""
Explanation: The Phase Lock Loop
The phase lock loop (PLL) is one of the Six classical feedback topologies in electrical engineering. The others being the Voltage-Voltage (Series-Shunt), Voltage-Current(Shunt-Shunt), Current-Current (Shunt-Shunt), Current-Voltage (Series-Series), and the Autoregressive Moving Average (ARMA, aka IIR Filter). The PLL differs from the rest in that it is temporal compersion feedback system that only works for oscillatory information. Looking at the diagram below for the generic classical PLL we see that it is made of Five (six if a frequency divider is added to the reference clock) components. Two of which the Phase Detector and the output frequency divider that make up the feedback loop are somewhat unique to the PLL and are the primary concern of this notebook.
<img src='PLL.png'>
The other components that are part of the forward path are the filter that helps take out some of the "phase noise" error that creeps into the PLL and is typical of the Low Pass variety. The reference oscillator that since the PLL controls phase and phase is a measure of temporal displacement against a reference and the Controlled Oscillator. In brief, the controlled oscillator is made to accelerate its temporal progression (how fast it oscillates) relative to the reference oscillator the error provided by the feedback loop. Where the error is then given as 
$$e(t)=K_{PD}(\Phi_{\text{ref}}(t)-\Phi_{\text{ocl}}(t)/N)$$ Where 
$K_{PD}$ is the transfer function of the Phase Detector that will be expanded upon shortly. the noting that the Transfer Function for the Voltage control oscillator is $K_{CO}$ and that of the filter is $H(s)$ the resulting open loop and closed loop gain can be found to be
$$A(s)=\dfrac{K_{PD} H(s) K_{CO}}{Ns}$$
$$G(s)=\dfrac{K_{PD} H(s) K_{CO}}{s+K_{PD} H(s) \dfrac{K_{CO}}{N}}$$
Phase Detectors
The phase detector (PD) is the only must-have component to a PLL that makes a PLL a PLL via calculating the phase offset error from a reference frequency source and the controlled frequency source via the negative feedback loop. It is the job of the PD to ensure that the waveform of the output is within some portion is in sync with the reference waveform thereby creating a phase lock. Where if the reface waveform and the controlled waveform are out of sync then the loop is said to be unlocked. While for analog PLL there are a variety of PDs which are mostly based on mixers (see Wiki Phase detector) for digital Phase Detectors there are basically only two kinds. The very primitive Negated XOR and the DFlipFlop Stat machine variety
Negated XOR
<img src='NXOR_PD.png'>
NXOR_PD myHDL implementation
End of explanation
"""


#clear peeker and create test signals
Peeker.clear()
clkREF=Signal(bool(0)); Peeker(clkREF, 'clkREF')
clkFB=Signal(bool(0)); Peeker(clkFB, 'clkFB')
LOCK=Signal(bool(0)); Peeker(LOCK, 'LOCK')
#this clk is a Witness clock refrance
clk=Signal(bool(0)); Peeker(clk, 'clk')

#bind the signals to the DUT
DUT=NXORPD(clkREF, clkFB, LOCK)

def NXORPD_TB(RefDelay=2, FBDelay=4):
    """
    Negated XOR Phase Detector Testbench
    Args:
        RefDelay (int; 2): refrance clock delay cyles compared to refrance
        FBDelay (int; 4): feedback clock delay cyles compared to refrance
        
    """
    #witness clock 
    @always(delay(1))
    def clkGen():
        clk.next=not clk
    
    #refrance clock
    @always(delay(RefDelay))
    def RefClkGen():
        clkREF.next=not clkREF
    #feedback clock
    @always(delay(FBDelay))
    def FBClkGen():
        clkFB.next=not clkFB
    
    #run the simulation
    @instance
    def stimulus():
        for i in range(100):
            yield clk.posedge
        
        raise StopSimulation()
    
    return instances()

sim=Simulation(DUT, NXORPD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=20)

#pull the sim data into a PD dataframe
NXORPDRes=Peeker.to_dataframe()
#reorder the collums
NXORPDRes=NXORPDRes.reindex(columns=['clk', 'clkREF', 'clkFB', 'LOCK']);NXORPDRes
#show the top ten
NXORPDRes.head(10)

#review what the Ref and FB clock values where when the PD was locked
NXORPDRes[NXORPDRes['clk']==1][NXORPDRes['LOCK']==1].head(10)

#review what the Ref and FB clock values where when the PD was unlocked
NXORPDRes[NXORPDRes['clk']==1][NXORPDRes['LOCK']==0].head(10)

"""
Explanation: NXOR_PD myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('NXORPD');

"""
Explanation: Verilog implementation
End of explanation
"""


@block
def SeqPD(clkREF, clkFB, UpOut, DownOut):
    """
    Sequential DFF Phase Detector
    I/O:
        clkREF (bool; in): Ref clock to Upper DFF
        clkFB (bool; in): Compare clock to Lower DFF
        UpOut (bool; ouput): Upper DFF ouput
        DownOut (bool; output): Lower DFF ouput
        
    """
    
    #and clear internal feedback sig
    clr = ResetSignal(0, active=0, async=True)

    
    #upper DFF
    @always(clkREF.posedge, clr.posedge)
    def UpD():
        if clr:
            UpOut.next=0
        else:
            UpOut.next=1
    
    #lower DFF
    @always(clkFB.posedge, clr.posedge)
    def DownD():
        if clr:
            DownOut.next=0
        else:
            DownOut.next=1
    
    #and clear
    @always_comb
    def clrLogic():
        clr.next= UpOut and DownOut
    
    return instances()

"""
Explanation: Sequntial  Phase Detector
<img src="SeqPD.png">
The Sequential PD is the most common digital phase detector around and while there are variations of this architecture that can be found they all based on this simple but ingenious architecture. The architecture consists of two DFF where unlike in a typical state machine where a master clock control the flipping of the DFFs and the Data line into the DFFs is part of the State machine feedback loop. Here the DFFs are each on an independent clock where here the upper DFF is tied to the Reference Clock and the lower one is tied to the Feedback Clock. Therefore each one will output a high signal at a rate determined by the frequency of there respective clocks. 
But that is not the end to the cleverness of this topology. The outputs of the DFFs are continuously compared by an AND gate such that only when the DFFs are in sync ($\omega_{\text{REF}}=\omega_{\text{FB}}$) will a very brief high spike will show up on both Next state lines of the DFF before the two DFFs are reset. For the other two conditions possible, only one of the two lines will have a high-value present. If $\omega_{\text{REF}}>\omega_{\text{FB}}$ then the lower output will be zero. And conversely if $\omega_{\text{REF}}<\omega_{\text{FB}}$ the upper output will be zero. 
The above conditions as described by Razavi yield the following state machine for the Sequential Phase Detector
<img src='SeqPDSM.png'>
Note that the actual phase detection is the average of the two output lines. Wich not shown here, where one method to find the average is by scaling the boolean outputs to digital words and then pass the resultant words to an average and then to a low pass filter in order to implement the PLL.
Seq_PD myHDL implementation
End of explanation
"""


#create the test signals
Peeker.clear()
clkREF=Signal(bool(0)); Peeker(clkREF, 'clkREF')
clkFB=Signal(bool(0)); Peeker(clkFB, 'clkFB')
UpOut=Signal(bool(0)); Peeker(UpOut, 'UpOut')
DownOut=Signal(bool(0)); Peeker(DownOut, 'DownOut')

#bind the test signals to the DUT
DUT=SeqPD(clkREF, clkFB, UpOut, DownOut)

def SeqPD_TB(RefDelay, FBDelay):
    """
    Test bench for Sequantial Testbench
    Args:
        RefDelay (int; 2): refrance clock delay cyles 
        FBDelay (int; 4): feedback clock delay cyles
    """
   
    #refrance clock
    @always(delay(RefDelay))
    def RefClkGen():
        clkREF.next=not clkREF
    
    #feedback clock
    @always(delay(FBDelay))
    def FBClkGen():
        clkFB.next=not clkFB
    
    #run the simulation
    @instance
    def stimulus():
        for i in range(50):
            yield clkREF.posedge
        
        raise StopSimulation()
    
    return instances()



"""
Explanation: Seq_PD myHDL testing
End of explanation
"""


#create the test signals
Peeker.clear()
clkREF=Signal(bool(0)); Peeker(clkREF, 'clkREF')
clkFB=Signal(bool(0)); Peeker(clkFB, 'clkFB')
UpOut=Signal(bool(0)); Peeker(UpOut, 'UpOut')
DownOut=Signal(bool(0)); Peeker(DownOut, 'DownOut')

#bind the test signals to the DUT
DUT=SeqPD(clkREF, clkFB, UpOut, DownOut)

sim=Simulation(DUT, SeqPD_TB(3, 2), *Peeker.instances()).run()
Peeker.to_wavedrom(start_time=0, stop_time=20)

"""
Explanation: Test when $\omega_{\text{REF}}>\omega_{\text{FB}}$
End of explanation
"""


#create the test signals
Peeker.clear()
clkREF=Signal(bool(0)); Peeker(clkREF, 'clkREF')
clkFB=Signal(bool(0)); Peeker(clkFB, 'clkFB')
UpOut=Signal(bool(0)); Peeker(UpOut, 'UpOut')
DownOut=Signal(bool(0)); Peeker(DownOut, 'DownOut')

#bind the test signals to the DUT
DUT=SeqPD(clkREF, clkFB, UpOut, DownOut)

sim=Simulation(DUT, SeqPD_TB(1, 1), *Peeker.instances()).run()
Peeker.to_wavedrom(start_time=0, stop_time=20)

"""
Explanation: Test when $\omega_{\text{REF}}=\omega_{\text{FB}}$
End of explanation
"""


#create the test signals
Peeker.clear()
clkREF=Signal(bool(0)); Peeker(clkREF, 'clkREF')
clkFB=Signal(bool(0)); Peeker(clkFB, 'clkFB')
UpOut=Signal(bool(0)); Peeker(UpOut, 'UpOut')
DownOut=Signal(bool(0)); Peeker(DownOut, 'DownOut')

#bind the test signals to the DUT
DUT=SeqPD(clkREF, clkFB, UpOut, DownOut)

sim=Simulation(DUT, SeqPD_TB(2, 3), *Peeker.instances()).run()
Peeker.to_wavedrom(start_time=0, stop_time=20)

"""
Explanation: Test when $\omega_{\text{REF}}<\omega_{\text{FB}}$
End of explanation
"""


DUT.convert()
VerilogTextReader('SeqPD');

"""
Explanation: Verilog implementation¶
End of explanation
"""


@block
def Div2FD(clkIN, clkOUT, rst):
    """
    1/2 fractial freancy divider
    I/O:
        clkIN (input bool): input clock signal
        clkOUT (ouput bool): 1/2 ouput clock signal
        rst (input bool): reset signal
    """
    W12=Signal(bool(0))
    
    @always(clkIN.posedge)
    def D1():
        if rst:
            W12.next=0
        else:
            W12.next=clkOUT
    
    @always(clkIN.posedge)
    def D2():
        if rst:
            clkOUT.next=0
        else:
            clkOUT.next= not W12
    
    return instances()

"""
Explanation: Fractional Frequency Dividers
Frequency Dividers (more properly called fractional frequency dividers) are and are not a  type of counter. In a traditional counter the counter would be run off a master clock to increment the counter and when the specified count is reached an indication signal would be given while also resetting the counter. In a fractional frequency divider, we can increment a counter but the incrimination is run off the input clock which may or may not be the master clock and the output of the counter reaching its count would be a then the new divided output clock. In addition, we can create "fractional" dividers such as $2/3$ via cascading a $1/2$ and a $1/3$ and modulating between them from another clock source to control the modulation. 
The reason that "fractional" is in quotes in regards to $2/3$ is that the frequency divider is not actually dividing by $2/3$ but is instead switching between a $1/2$ and a $1/3$ divider. Thus $2/3$ divider is a notational misnomer. But by cascading fixed and variable dividers with counters to control the modulation based on the clock being cascaded from large fractional division can be optioned
So as stated frequency dividers are and are not a counter through  some of the more advanced programmable frequency dividers such as http://tremaineconsultinggroup.com/fractional-divider-in-verilog/ (source code: https://bitbucket.org/BrianTremaine/fractional_divide/src/a68c67979c80a453d4f7dfd82f5bf90d604393f1/hardware/frac_divider.v?at=master&fileviewer=file-view-default) ) are much more like counters then the primitive ones that will be discussed here
Divide by 2
<img src="FD2.png">
Divide by 2 myHDL implementation
End of explanation
"""


Peeker.clear()
clkIN=Signal(bool(0)); Peeker(clkIN, 'clkIN')
clkOUT=Signal(bool(0)); Peeker(clkOUT, 'clkOUT')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=Div2FD(clkIN, clkOUT, rst)

def Div2FD_TB():
    
    #input clock source
    @always(delay(1))
    def ClkGen():
        clkIN.next=not clkIN
        
    #run the simulation
    @instance
    def stimulus():
        for i in range(21):
            yield clkIN.posedge
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, Div2FD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=21)

"""
Explanation: Divide by 2 myHDL testing
End of explanation
"""


DUT.convert()
VerilogTextReader('Div2FD');

"""
Explanation: Verilog implementation
End of explanation
"""


@block
def Div3FD(clkIN, clkOUT, rst):
    """
    1/3 fractial freancy divider
    I/O:
        clkIN (input bool): input clock signal
        clkOUT (ouput bool): 1/2 ouput clock signal
        rst (input bool): reset signal
    """
    W1A, WA2=[Signal(bool(0)) for _ in range(2)]
    
    @always(clkIN.posedge)
    def D1():
        if rst:
            W1A.next=0
        else:
            W1A.next=clkOUT
    
    @always(clkIN.posedge)
    def D2():
        if rst:
            clkOUT.next=0
        else:
            clkOUT.next= not WA2
    
    @always_comb
    def And():
        WA2.next=W1A and clkOUT
    
    return instances()

"""
Explanation: Divide by 3
<img src="FD3.png">
Divide by 3 myHDL implementation
End of explanation
"""


Peeker.clear()
clkIN=Signal(bool(0)); Peeker(clkIN, 'clkIN')
clkOUT=Signal(bool(0)); Peeker(clkOUT, 'clkOUT')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=Div3FD(clkIN, clkOUT, rst)

def Div3FD_TB():
    
    #input clock source
    @always(delay(1))
    def ClkGen():
        clkIN.next=not clkIN
        
    #run the simulation
    @instance
    def stimulus():
        for i in range(31):
            yield clkIN.posedge
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, Div3FD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=19)

"""
Explanation: Divide by 3 myHDL testing
End of explanation
"""


DUT.convert()
VerilogTextReader('Div3FD');

"""
Explanation: Verilog implementation
End of explanation
"""


@block
def Div23FD(clkIN, ModControl, clkOUT, rst):
    """
    2/3 fractial freancy divider
    I/O:
        clkIN (input bool): input clock signal
        ModControl (input bool): modulation switching signal
        low is 1/3 high is 1/2
        clkOUT (ouput bool): 1/2 ouput clock signal
        rst (input bool): reset signal
    """
    W1O, WOA, WA2=[Signal(bool(0)) for _ in range(3)]
    
    @always(clkIN.posedge)
    def D1():
        if rst:
            W1O.next=0
        else:
            W1O.next=clkOUT
    
    @always(clkIN.posedge)
    def D2():
        if rst:
            clkOUT.next=0
        else:
            clkOUT.next=not WA2
    
    @always_comb
    def OR():
        WOA.next=W1O or ModControl
    
    @always_comb
    def AND():
        WA2.next=clkOUT and WOA
    
    
    return instances()

"""
Explanation: Divide by 2/3
<img src="FD23.png">
This is a simple hybridization of the $1/2$ and the $1/3$ frequency divider that is modulated between the two by a ModControl Signal at the or gate to create a $2/3$ frequency divider
Divide by 2/3 myHDL implementation
End of explanation
"""


Peeker.clear()
clkIN=Signal(bool(0)); Peeker(clkIN, 'clkIN')
ModControl=Signal(bool(1)); Peeker(ModControl, 'ModControl')
clkOUT=Signal(bool(0)); Peeker(clkOUT, 'clkOUT')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=Div23FD(clkIN, ModControl, clkOUT, rst)

def Div23FD_TB():
    
    #input clock source
    @always(delay(1))
    def ClkGen():
        clkIN.next=not clkIN
        
    #run the simulation
    @instance
    def stimulus():
        for i in range(31):
            yield clkIN.posedge
            if i>4:
                ModControl.next=0
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, Div23FD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=8)

Peeker.to_wavedrom(start_time=10, stop_time=23)

Peeker.to_wavedrom(start_time=0, stop_time=23)

"""
Explanation: Divide by 2/3 myHDL testing
End of explanation
"""


DUT.convert()
VerilogTextReader('Div23SFD');

"""
Explanation: Verilog implementation
End of explanation
"""


@block
def Div45FD(clkIN, ModControl, clkOUT, rst):
    """
    4/5 fractial freancy divider
    I/O:
        clkIN (input bool): input clock signal
        ModControl (input bool): modulation switching signal
        low is 1/4 high is 1/5
        clkOUT (ouput bool): 1/2 ouput clock signal
        rst (input bool): reset signal
    """
    WNA11, W12, W2NA1, W2NA2, WNA23, W3NA1=[Signal(bool(0)) for _ in range(6)]
    
    
    @always_comb
    def NAND1():
        WNA11.next=not(W2NA1 and W3NA1 )
        

    @always(clkIN.posedge)
    def D1():
        if rst:
            W12.next=0
            clkOUT.next=0
        else:
            W12.next=WNA11
            clkOUT.next= WNA11
            
    @always(clkIN.posedge)
    def D2():
        if rst:
            W2NA1.next=0
            W2NA2.next=0
        else:
            W2NA1.next=W12
            W2NA2.next=not W12
    
    @always_comb
    def NAND2():
        WNA23.next=not(W2NA2 and ModControl)
    
    
    
    @always(clkIN.posedge)
    def D3():
        if rst:
            W3NA1.next=0
        else:
            W3NA1.next=WNA23
    
    
    
    
    return instances()

"""
Explanation: Divide by 4/5
<img src='FD45.png'>
Divide by 4/5 myHDL implementation
End of explanation
"""


Peeker.clear()
clkIN=Signal(bool(0)); Peeker(clkIN, 'clkIN')
ModControl=Signal(bool(0)); Peeker(ModControl, 'ModControl')
clkOUT=Signal(bool(0)); Peeker(clkOUT, 'clkOUT')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=Div45FD(clkIN, ModControl, clkOUT, rst)

def Div45FD_TB():
    
    #input clock source
    @always(delay(1))
    def ClkGen():
        clkIN.next=not clkIN
        
    #run the simulation
    @instance
    def stimulus():
        for i in range(40):
            yield clkIN.posedge
            if i>12:
                ModControl.next=1
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, Div45FD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=20)

Peeker.to_wavedrom(start_time=20, stop_time=40)

Peeker.to_wavedrom(start_time=0, stop_time=40)

"""
Explanation: Divide by 4/5 myHDL testing
End of explanation
"""


DUT.convert()
VerilogTextReader('Div45FD');

"""
Explanation: Verilog implementation
End of explanation
"""


@block
def Div6FD(clkIN, clkOUT, rst):
    """
    1/6 fractial freancy divider via cascaded 2 and 3 dividers
    using two `Div23SFD`
    I/O:
        clkIN (input bool): input clock signal
        clkOUT (ouput bool): 1/6 ouput clock signal
        rst (input bool): reset signal
    """
    clkMid=Signal(bool(0))
    MC2=Signal(bool(1));  MC3=Signal(bool(0))
    
    D2=Div23FD(clkIN, MC2, clkMid, rst)
    D3=Div23FD(clkMid, MC3, clkOUT, rst)
    
    return instances()

"""
Explanation: Divide by 6 via cascaded 2 and 3
Divide by 6 myHDL implementation
End of explanation
"""


Peeker.clear()
clkIN=Signal(bool(0)); Peeker(clkIN, 'clkIN')
clkOUT=Signal(bool(0)); Peeker(clkOUT, 'clkOUT')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=Div6FD(clkIN, clkOUT, rst)

def Div6FD_TB():
    
    #input clock source
    @always(delay(1))
    def ClkGen():
        clkIN.next=not clkIN
        
    #run the simulation
    @instance
    def stimulus():
        for i in range(31):
            yield clkIN.posedge
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, Div6FD_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom(start_time=0, stop_time=21)

"""
Explanation: Divide by 6 myHDL testing
End of explanation
"""


DUT.convert()
VerilogTextReader('Div6FD');

"""
Explanation: Verilog implementation
End of explanation
"""


