import numpy as np
import pandas as pd
from sympy import *
init_printing()

from myhdl import *
from myhdlpeek import *
import random

from sympy_myhdl_tools import *

import  scipy.signal as sig
import matplotlib.pyplot as plt
%matplotlib inline

"""
Explanation: \title{Digital Arithmetic Cells with myHDL}
\author{Steven K Armour}
\maketitle
Table of Contents
<p><div class="lev1 toc-item"><a href="#Refs" data-toc-modified-id="Refs-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Refs</a></div><div class="lev1 toc-item"><a href="#Python-Libraries-Used" data-toc-modified-id="Python-Libraries-Used-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Python Libraries Used</a></div><div class="lev1 toc-item"><a href="#Compression-of-Number-System-Values" data-toc-modified-id="Compression-of-Number-System-Values-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Compression of Number System Values</a></div><div class="lev1 toc-item"><a href="#Computer-Number-Systems" data-toc-modified-id="Computer-Number-Systems-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Computer Number Systems</a></div><div class="lev2 toc-item"><a href="#Decimal-to-Binary" data-toc-modified-id="Decimal-to-Binary-41"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Decimal to Binary</a></div><div class="lev2 toc-item"><a href="#Decimal-to-hex" data-toc-modified-id="Decimal-to-hex-42"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>Decimal to hex</a></div><div class="lev2 toc-item"><a href="#Decmial-to-oct" data-toc-modified-id="Decmial-to-oct-43"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>Decmial to oct</a></div><div class="lev1 toc-item"><a href="#Addition" data-toc-modified-id="Addition-5"><span class="toc-item-num">5&nbsp;&nbsp;</span>Addition</a></div><div class="lev2 toc-item"><a href="#Half-Adder" data-toc-modified-id="Half-Adder-51"><span class="toc-item-num">5.1&nbsp;&nbsp;</span>Half Adder</a></div><div class="lev2 toc-item"><a href="#Full-Adder" data-toc-modified-id="Full-Adder-52"><span class="toc-item-num">5.2&nbsp;&nbsp;</span>Full Adder</a></div><div class="lev2 toc-item"><a href="#Ripple-Adder" data-toc-modified-id="Ripple-Adder-53"><span class="toc-item-num">5.3&nbsp;&nbsp;</span>Ripple Adder</a></div><div class="lev2 toc-item"><a href="#Ripple-Adder-using-bitvectors" data-toc-modified-id="Ripple-Adder-using-bitvectors-54"><span class="toc-item-num">5.4&nbsp;&nbsp;</span>Ripple Adder using bitvectors</a></div><div class="lev2 toc-item"><a href="#Adder-Carry-Look-Ahead" data-toc-modified-id="Adder-Carry-Look-Ahead-55"><span class="toc-item-num">5.5&nbsp;&nbsp;</span>Adder Carry Look Ahead</a></div><div class="lev2 toc-item"><a href="#Adder-Behavioral" data-toc-modified-id="Adder-Behavioral-56"><span class="toc-item-num">5.6&nbsp;&nbsp;</span>Adder Behavioral</a></div><div class="lev1 toc-item"><a href="#Suptraction" data-toc-modified-id="Suptraction-6"><span class="toc-item-num">6&nbsp;&nbsp;</span>Suptraction</a></div><div class="lev2 toc-item"><a href="#Two-Bit-Suptraction-(Need-to-cheeck)" data-toc-modified-id="Two-Bit-Suptraction-(Need-to-cheeck)-61"><span class="toc-item-num">6.1&nbsp;&nbsp;</span>Two Bit Suptraction (Need to cheeck)</a></div><div class="lev2 toc-item"><a href="#Suptraction-Behavioral" data-toc-modified-id="Suptraction-Behavioral-62"><span class="toc-item-num">6.2&nbsp;&nbsp;</span>Suptraction Behavioral</a></div><div class="lev1 toc-item"><a href="#Multiplication" data-toc-modified-id="Multiplication-7"><span class="toc-item-num">7&nbsp;&nbsp;</span>Multiplication</a></div><div class="lev2 toc-item"><a href="#Multiplication-Beahavioral" data-toc-modified-id="Multiplication-Beahavioral-71"><span class="toc-item-num">7.1&nbsp;&nbsp;</span>Multiplication Beahavioral</a></div><div class="lev1 toc-item"><a href="#Division" data-toc-modified-id="Division-8"><span class="toc-item-num">8&nbsp;&nbsp;</span>Division</a></div><div class="lev1 toc-item"><a href="#comparator" data-toc-modified-id="comparator-9"><span class="toc-item-num">9&nbsp;&nbsp;</span>comparator</a></div><div class="lev1 toc-item"><a href="#Intergration" data-toc-modified-id="Intergration-10"><span class="toc-item-num">10&nbsp;&nbsp;</span>Intergration</a></div>

# Refs
@book{brown_vranesic_2014,
place={New York, NY},
edition={3},
title={Fundamentals of digital logic with Verilog design},
publisher={McGraw-Hill},
author={Brown, Stephen and Vranesic, Zvonko G},
year={2014}
},

@book{lameres_2017,
title={Introduction to logic circuits & logic design with Verilog},
publisher={springer},
author={LaMeres, Brock J},
year={2017}
}

@misc{four bit adder - rosetta code-myhdl_2017,
url={https://rosettacode.org/wiki/Four_bit_adder#MyHDL},
journal={Rosettacode.org},
year={2017}
},

@book{cavanagh_2010,
place={Boca Raton, FL},
title={Computer arithmetic and Verilog HDL fundamentals},
publisher={CRC Press},
author={Cavanagh, Joseph},
year={2010}
},

@misc{peeker_hier_add_2017,
url={http://www.xess.com/static/media/pages/peeker_hier_add.html},
journal={Xess.com},
year={2017}
},
Christopher Felton's CIC Exsample from myHDL old site (https://github.com/jandecaluwe/site-myhdl-retired/blob/master/_ori/pages/projects/gciccomplete.txt)


# Python Libraries Used
End of explanation
"""


ConversionTable=pd.DataFrame(columns=['Decimal'])

ConversionTable['Decimal']=np.arange(0, 21)
ConversionTable['Binary']=[bin(i, 3) for i in np.arange(0, 21)]
ConversionTable['hex']=[hex(i) for i in np.arange(0, 21)]
ConversionTable['oct']=[oct(i) for i in np.arange(0, 21)]
ConversionTable

"""
Explanation: Compression of Number System Values
End of explanation
"""


def DecimialtoBaseN(dec, base):
    quotant=[dec]; remander=[]
    while True:
        q, r=np.divmod(quotant[-1], base)
        quotant.append(q); remander.append(r)
        if q==0: break
    
    TwosProd=[]
    for i in range(len(remander)):
        TwosProd.append(remander[i]*base**i)
    return quotant, remander, TwosProd[::-1], np.sum(TwosProd)

"""
Explanation: Computer Number Systems
Decimal to Binary
End of explanation
"""


binarySum=lambda a, b, bits=2: np.binary_repr(a+b, bits)

for i in [[0,0], [0,1], [1,0], [1,1]]:
    print(f'{i[0]} + {i[1]} yield {binarySum(*i)}')

"""
Explanation: Decimal to hex
Decmial to oct
Addition
End of explanation
"""


S_out, C_out=symbols('S_out, C_out')

x_1in, x_2in, y_out=symbols('x_1in, x_2in, y_out')
SEq=Eq(S_out, x_1in^x_2in)
print(SEq)
SEq_TT=TruthTabelGenrator(SEq)
SEq_TT

CEq=Eq(C_out, x_1in & x_2in)
CEq_TT=TruthTabelGenrator(CEq)
print(CEq)
CEq_TT

pd.merge(SEq_TT, CEq_TT[CEq_TT.columns.difference(SEq_TT.columns)], left_index=True, right_index=True)

"""
Explanation: if we split the yileded output up we find that the right most place is the 'Sum' and the next place to the left if the 'carry'
therfore we can posttulate the following
End of explanation
"""


binarySum=lambda a, b, bits=3: np.binary_repr(a+b, bits)

for i in [[0,0], [0,1], [1,0], [1,1], [0, 2], [1, 2], [2,2],
          [0, 3], [1, 3], [2, 3], [3,3]]:
    print(f'{i[0]} + {i[1]} yield {binarySum(*i)}')

"""
Explanation: Passing the carry
End of explanation
"""


C_in=symbols('C_in')
Sum3Eq=Eq(S_out, x_1in ^x_2in^C_in)
print(Sum3Eq)
SEq_TT=TruthTabelGenrator(Sum3Eq)
SEq_TT

C3Eq=Eq(C_out, (x_1in & x_2in) | ((x_1in & x_2in)& C_in))
CEq_TT=TruthTabelGenrator(C3Eq)
print(CEq)
CEq_TT

pd.merge(SEq_TT, CEq_TT[CEq_TT.columns.difference(SEq_TT.columns)], left_index=True, right_index=True)

"""
Explanation: We can see that once exceded the binary repersentation of 2 we have a carry to the next bit
End of explanation
"""


def HalfAdder(x_1in, x_2in, S_out, C_out):
    @always_comb
    def logic():
        S_out.next=x_1in ^ x_2in
        C_out.next=x_1in & x_2in
    
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, S_out, C_out=[Signal(bool(0)) for _ in range(4)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in')
Peeker(S_out, 'y_out'); Peeker(C_out, 'C_out')

#make an instatince of the NotGate as the DUT
DUT=HalfAdder(x_1in=x_1in, x_2in=x_2in, S_out=S_out, C_out=C_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='HalfAdder simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))

toVerilog(HalfAdder, x_1in, x_2in, S_out, C_out)
#toVHDL(And3Gate, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('HalfAdder')

"""
Explanation: Half Adder
End of explanation
"""


def FullAdder21(x_1in, x_2in, C_in, S_out, C_out):
    @always_comb
    def logic():
        S_out.next=x_1in ^ x_2in ^C_in
        C_out.next=(x_1in and x_2in) or (x_1in and C_in) or (x_2in and C_in)
    
    return logic

"""
Explanation: Full Adder
End of explanation
"""


#create the test signals and intilize value to both be false(0)
x_1in, x_2in, C_in, S_out, C_out=[Signal(bool(0)) for _ in range(5)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(C_in, 'C_in')
Peeker(S_out, 'y_out'); Peeker(C_out, 'C_out')


#make an instatince of the NotGate as the DUT
DUT=FullAdder21(x_1in=x_1in, x_2in=x_2in, C_in=C_in, S_out=S_out, C_out=C_out)

inputs=[x_1in, x_2in, C_in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='FullAdder21 simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


FA21DF=MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))
FA21DF[['x_1in', 'x_2in','C_in',  'y_out','C_out' ]]

"""
Explanation: ! need to change the order of the inputs in the simulator so that Cin is last
End of explanation
"""


def FullAdder(x_1in, x_2in, C_in, S_out, C_out):
    
    S_1out=Signal(bool()); C_1out=Signal(bool())
    HalfAdder1=HalfAdder(x_1in=x_1in, x_2in=C_in, 
                         S_out=S_1out, C_out=C_1out)
    
    C_2out=Signal(bool())
    HalfAdder2=HalfAdder(x_1in=S_1out, x_2in=x_2in, 
                         S_out=S_out, C_out=C_2out)
    
    @always_comb
    def C_outLogic():
        C_out.next= C_1out or C_2out
    
    return  HalfAdder1, HalfAdder2, C_outLogic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, C_in, S_out, C_out=[Signal(bool(0)) for _ in range(5)]

#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(C_in, 'C_in')
Peeker(S_out, 'y_out'); Peeker(C_out, 'C_out')


#make an instatince of the NotGate as the DUT
DUT=FullAdder(x_1in=x_1in, x_2in=x_2in, C_in=C_in, S_out=S_out, C_out=C_out)

inputs=[x_1in, x_2in, C_in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='FullAdder simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


FARDF=MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))
FARDF[['x_1in', 'x_2in','C_in',  'y_out','C_out' ]]

"""
Explanation: Ripple Adder
Ripple adders are a exsample of composistion  built by using previoues instaninces
End of explanation
"""


def AdderBehavioral(x_1in, x_2in, S_out):
    @always_comb
    def logic():
        S_out.next=x_1in+x_2in
    return logic

Peeker.clear()
BITWidth=3
x_1in=Signal(intbv(0)[BITWidth:]); Peeker(x_1in, 'x_1in')
x_2in=Signal(intbv(0)[BITWidth:]); Peeker(x_2in, 'x_2in')
S_out=Signal(intbv(0)[BITWidth+1:]); Peeker(S_out, 'S_out')

DUT=AdderBehavioral(x_1in, x_2in, S_out)

def AdderBehavioral_TB():
    for i in ((x,y) for x in range(2**BITWidth) for y in range(2**BITWidth)):
        x_1in.next, x_2in.next=i
        
        yield delay(1)
    
    raise StopSimulation
sim=Simulation(DUT, AdderBehavioral_TB(), *Peeker.instances()).run()        
Peeker.to_wavedrom(tock=True,start_time=0, stop_time=3*2**BITWidth -1,
                  title='AdderBehavioral simulation',
                  caption=f'bitwidth inputs:{BITWidth}, outputs:{BITWidth+1}')


#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())



x_1in, x_2in=[Signal(intbv(0)[BITWidth:]) for _ in range(2)]
S_out=Signal(intbv(0)[BITWidth+1:])
toVerilog(AdderBehavioral, x_1in, x_2in, S_out)
#toVHDL(AdderBehavioral, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('AdderBehavioral')

"""
Explanation: Ripple Adder using bitvectors
Adder Carry Look Ahead
Adder Behavioral
End of explanation
"""


def FullSup21(x_1in, x_2in, B_in, S_out, B_out):
    @always_comb
    def logic():
        S_out.next=x_1in ^ (not x_2in) ^B_in
        B_out.next=(x_1in and  (not x_2in)) or (x_1in and B_in) or ((not x_2in) and B_in)
    
    return logic

#create the test signals and intilize value to both be false(0)
x_1in, x_2in, S_out, B_out=[Signal(bool(0)) for _ in range(4)]
B_in=Signal(bool(1))
#Peeker is helper libary for viewing wavefrom outputs and run the sim inside
#jupyter notebooks
#clear any previeese data loaded into peeker
Peeker.clear()

#load and name the signals to watch into peeker
Peeker(x_1in, 'x_1in'); Peeker(x_2in, 'x_2in'); Peeker(B_in, 'B_in')
Peeker(S_out, 'y_out'); Peeker(B_out, 'B_out')


#make an instatince of the NotGate as the DUT
DUT=FullSup21(x_1in=x_1in, x_2in=x_2in, B_in=B_in, S_out=S_out, B_out=B_out)

inputs=[x_1in, x_2in]

sim=Simulation(DUT, Combo_TB(inputs), *Peeker.instances()).run()        
Peeker.to_wavedrom(start_time=0, stop_time=2*2**len(inputs), tock=True,
                  title='FullSup21 simulation',
                  caption=f'after clock cycle {2**len(inputs)-1} ->random input')


"""
Explanation: Suptraction
Two Bit Suptraction (Need to cheeck)
End of explanation
"""


def SuptractionBehavioral(x_1in, x_2in, S_out):
    @always_comb
    def logic():
        S_out.next=x_1in-x_2in
    return logic

Peeker.clear()
BITWidth=3
x_1in=Signal(intbv(0)[BITWidth:]); Peeker(x_1in, 'x_1in')
x_2in=Signal(intbv(0)[BITWidth:]); Peeker(x_2in, 'x_2in')
S_out=Signal(intbv(0, min=-2**BITWidth, max=2**BITWidth)); Peeker(S_out, 'S_out')

DUT=SuptractionBehavioral(x_1in, x_2in, S_out)

def SuptractionBehavioral_TB():
    for i in ((x,y) for x in range(2**BITWidth) for y in range(2**BITWidth)):
        x_1in.next, x_2in.next=i
        
        yield delay(1)
    
    raise StopSimulation
sim=Simulation(DUT, AdderBehavioral_TB(), *Peeker.instances()).run()        
Peeker.to_wavedrom(tock=True,start_time=0, stop_time=3*2**BITWidth -1,
                  title='SuptractionBehavioral simulation',
                  caption=f'bitwidth inputs:{BITWidth}, outputs:{BITWidth+1}')


#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())


x_1in, x_2in=[Signal(intbv(0)[BITWidth:]) for _ in range(2)]
S_out=S_out=Signal(intbv(0, min=-2**BITWidth, max=2**BITWidth))
toVerilog(SuptractionBehavioral, x_1in, x_2in, S_out)
#toVHDL(SuptractionBehavioral, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('SuptractionBehavioral')

"""
Explanation: Suptraction Behavioral
End of explanation
"""


def MultiplyBehavioral(x_1in, x_2in, P_out):
    @always_comb
    def logic():
        P_out.next=x_1in*x_2in
    return logic

Peeker.clear()
BITWidth=3
x_1in=Signal(intbv(0)[BITWidth:]); Peeker(x_1in, 'x_1in')
x_2in=Signal(intbv(0)[BITWidth:]); Peeker(x_2in, 'x_2in')
P_out=Signal(intbv(0)[BITWidth**2:]); Peeker(P_out, 'P_out')

DUT=MultiplyBehavioral(x_1in, x_2in, P_out)

def MultiplyBehavioral_TB():
    for i in ((x,y) for x in range(2**BITWidth) for y in range(2**BITWidth)):
        x_1in.next, x_2in.next=i
        
        yield delay(1)
    
    raise StopSimulation
sim=Simulation(DUT, MultiplyBehavioral_TB(), *Peeker.instances()).run()        
Peeker.to_wavedrom(tock=True,start_time=0, stop_time=3*2**BITWidth -1,
                  title='MultiplyBehavioral simulation',
                  caption=f'bitwidth inputs:{BITWidth}, outputs:{BITWidth+1}')


#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())

x_1in, x_2in=[Signal(intbv(0)[BITWidth:]) for _ in range(2)]
P_out=Signal(intbv(0)[BITWidth**2:])
toVerilog(MultiplyBehavioral, x_1in, x_2in, P_out)
#toVHDL(MultiplyBehavioral, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('MultiplyBehavioral')

"""
Explanation: Multiplication
Multiplication Beahavioral
End of explanation
"""


z, n=symbols('z, n')
yn=Function('y')(n)
yn_1=Function('y')(n-1)
xn=Function('x')(n)
IntEq=Eq(yn, yn_1+xn); IntEq

"""
Explanation: Division
comparator
Intergration
$$\int f(x)dx \approx \sum_{i=1}^{\infty} w_i f(x_i) +r_i$$
ignoring the residual $r_i$ and setting the weight $w_i=1$ for all $i$ we can make a very very crude approximation of the integral to be 
$$y=\int f(x)dx  \approx f(x_i)+f(x_{i-1})$$
wich is better written as
End of explanation
"""


Y=Function('Y')(z); X=Function('X')(z)
Equat=IntEq
for j in [yn, yn_1]:
    zsups=expand(z**-(list(j.args))[0])
    zsups
    Equat=Equat.subs(j, z**(list(j.args))[0])
Equat=expand(Equat).subs(z**n, Y)
for j in [xn]:
    zsups=expand(z**-(list(j.args))[0])
    zsups
    Equat=Equat.subs(j, z**(list(j.args))[0])
Equat=expand(Equat).subs(z**n, X)
Equat

"""
Explanation: Perform a primitive Z transform on the above equation
(note at this time sympy has no Z transform, so I am hacking one here) we get
End of explanation
"""


TF=solve(Equat, Y)[0]/X; TF

"""
Explanation: that then yields the Transfer function $H(z)=\dfrac{Y(z)}{X(z)}$
End of explanation
"""


TFnum, TFden=fraction(TF); TFnum, TFden

TFCoefN=lambda NumDen: [float(i) for i in Poly(NumDen, z).coeffs()]
TFnumC=TFCoefN(TFnum); TFdenC=TFCoefN(TFden)
TFnumC, TFdenC

"""
Explanation: the resulting Transfer Function is analyzed by splitting apart the numurator and denomantior to find zeros and poles respectively as well as the coefficient
End of explanation
"""


TFN=sig.TransferFunction(TFnumC, TFdenC, dt=1)
w, mag, phase = sig.dbode(TFN)

fig, [ax1, ax2]=plt.subplots(nrows=2, ncols=1)
ax1.semilogx(w, mag, label='Mag')
ax1.set_ylabel('mag')
ax2.semilogx(w, phase)
ax2.set_ylabel('phase')
ax2.set_xlabel('ang freq')



#The following will not synth but will run in peeker ?
ysim, xsim=symbols('y,x')
sups={xn:xsim, yn_1:ysim}
IntEq.rhs.subs(sups)
toMyHDL=lambdify((xsim, ysim), IntEq.rhs.subs(sups), dummify=False)

def IntCurde(x_in, y_out, clk, rst):
    @always(clk.posedge)
    def logic():
        if rst:
            y_out.next=0
        else:
            y_out.next=x_in+y_out
            #!!! Houston we have a problom here
            #this will not synthesis to HDL but will run in Peeker
            #y_out.next=toMyHDL(x=x_in, y=y_out)
    return logic

BITWidth=3

Peeker.clear()
x_in=Signal(intbv(int(BITWidth*random.uniform(-1, 1)), min=-10, max=10)); Peeker(x_in, 'x_in')
y_out=Signal(intbv(0, min=-40, max=40)); Peeker(y_out, 'y_out')

clk=Signal(bool(0)); Peeker(clk, 'clk')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=IntCurde(x_in, y_out, clk, rst)
def Int_TB():
    
    @always(delay(1))
    def clkgen():
        clk.next = not clk
    
    @always(clk.posedge)
    def ith():
        x_in.next=int(BITWidth*random.uniform(0, 2))
    
    return ith, clkgen

sim=Simulation(DUT, Int_TB(), *Peeker.instances()).run(15)
Peeker.to_wavedrom(tock=True)

x_in=Signal(intbv(0, min=-10, max=10))
y_out=Signal(intbv(0, min=-40, max=40))
clk=Signal(bool(0)); rst=Signal(bool(0))
toVerilog(IntCurde, x_in, y_out, clk, rst)
_=VerilogTextReader('IntCurde')

"""
Explanation: these coefinents for the poles and zeros can be pulled into scipy's signals modul for further anylsis via
End of explanation
"""


