From Python to silicon
 
import sys, os
 
import numpy as np
from numpy import pi, sin, cos, log10, log2, ceil
from numpy.random import uniform
from numpy.fft import fft, fftshift
from scipy.signal import freqz, step, lti
 
from myhdl import *
 
import pylab as plt
 
Nloops  = 100
Nfft    = 4096
MaxGain = 1
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def pass_thru(x, dvi, y, dvo):
    """
    Place holder
    """
 
    @always_comb
    def rtl():
        y.next   = x
        dvo.next = dvi
 
    return rtl
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def cmb_dly(clk, x, dvi, y):
    """
    Simple delay used with the comb filter
    """
 
    @always(clk.posedge)
    def rtl():
        if dvi:
            y.next   = x
 
    return rtl 
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def accum(clk, rst, x, dvi, y, dvo):
    """
    Simple Integrator
    """    
 
    @always(clk.posedge)
    def rtl():
        if rst:
            y.next = 0
        else:
            if dvi:
                y.next = y + x
                dvo.next = True
            else:
                dvo.next = False
 
    return rtl
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def combd(clk, rst, x, dvi, y, dvo, D=5):
    """
    Simple Comb (difference) filter with parameterizable delay
    """
    Q = len(x)-1
    L = 2**Q
 
    dlyi = [None for i in range(D)]
    dlyx = [Signal(intbv(0, min=-L, max=L)) for i in range(D)]
 
    subx = dlyx[D-1]
 
    for ii in range(D):
        if ii == 0:
            dlyi[ii] = cmb_dly(clk, x, dvi, dlyx[ii])
        else:
            dlyi[ii] = cmb_dly(clk, dlyx[ii-1], dvi, dlyx[ii])
 
    @always(clk.posedge)
    def rtl():
        if rst:
            y.next = 0
        else:
            if dvi:
                y.next   = x - subx
                dvo.next = True
            else:
                dvo.next = False
 
    return rtl, dlyi
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def decimate(clk, rst, x, dvi, y, dvo, R=8):
    """
    """
    Qc  = ceil(log2(R))
    cnt = Signal(intbv(0, max=2**Qc))
 
    @always(clk.posedge)
    def rtl1():
        if rst:
            y.next = 0
        else:
            if cnt == 0:
                y.next  = x
                dv.next = True
            else:
                y.next  = 0
                dv.next = False
 
 
    @always(clk.posedge)
    def rtl2():
        if rst:
            cnt.next = 0
        else:
            if cnt == R-1:
                cnt.next = 0
            else:
                cnt.next = cnt + 1
 
 
    return rtl1, rtl2
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def interpolate(clk, rst, x, dvi, y, dvo, R=8):
    """
    """
    Qc  = ceil(log2(R))
    cnt = Signal(intbv(0, max=2**Qc))
 
    @always(clk.posedge)
    def rtl1():
        if rst:
            y.next = 0
        else:
            if dvi:
                y.next  = x
                dv.next = True
            elif cnt > 0:
                y.next  = 0
                dv.next = True
            else:
                y.next  = 0
                dv.next = False
 
 
    @always(clk.posedge)
    def rtl2():
        if rst:
            cnt.next = 0
        else:
            if dvi:
                cnt.next = R-1
            elif cnt > 0:
                cnt.next = cnt + 1
 
 
    return rtl1, rtl2
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def cic(clk, rst, x, dvi, y, dvo, M=3, D=8, R=8, Q=7, Type=None):
    """ Cascade Integrator-Comb (CIC) Filter
 
    This module is an fixed-point implementation of CIC filter with configurable
    parameters.
 
    Ports:
    ------
    clk:  System clock, must be equal to or greater than the max
          sample rate after interpolation or before decimation
    rst:  System reset
    x:    2's compliment input
    dvi:  data valid input, flow control signal for the different rates
    y:    2's compliment output
    dvo:  data valid output, flow control signal for the different rates
 
    Parameters:
    -----------
    M:      CIC order
    D:      Comb delay
    R:      Decimation/interpolation value
    Q:      Input word size (7,15,31...)
    Type:   'Dec', 'Int', or None
    """
    Qi = len(x)-1
    Qo = len(y)-1
    Li = 2**Qi
    Lo = 2**Qo
 
    Cmbi = [None for i in range(M)]
    Acci = [None for i in range(M)]
    xcmb = [Signal(intbv(0, min=-Lo, max=Lo)) for i in range(M)]
    xacc = [Signal(intbv(0, min=-Lo, max=Lo)) for i in range(M)]
    xi   = Signal(intbv(0, min=-Lo, max=Lo))
 
    dvoi = Signal(False)
    dvoc = [Signal(False) for i in range(M)]
    dvoa = [Signal(False) for i in range(M)]
 
    # Add Interpolation, Up sample then filter
    if Type == 'Int' :
        Int = interploate(clk, rst, x, dvi, xi, dvoi, R)
    else:
        Int = pass_thru(x, dvi, xi, dvoi)
 
    # Create the Comb Stages
    for ii in range(M):
        if ii == 0:
            Cmbi[ii] = combd(clk, rst, xi, dvoi, xcmb[ii], dvoc[ii], D)
        else:
            Cmbi[ii] = combd(clk, rst, xcmb[ii-1], dvoc[ii-1], xcmb[ii], dvoc[ii], D)
 
    # Create the Integrator Stages
    for ii in range(M):        
        if ii == 0:
            Acci[ii] = accum(clk, rst, xcmb[M-1], dvoc[M-1], xacc[ii], dvoa[ii])
        else:
            Acci[ii] = accum(clk, rst, xacc[ii-1], dvoa[ii-1], xacc[ii], dvoa[ii])
 
    # Final Decimation Stage, filter then down sample
    if Type == 'Dec':
        Dec = decimate(clk, rst, xacc[M-1], dvoa[M-1], y, dvo, R)
    else:
        Dec = pass_thru(xacc[M-1], dvoa[M-1], y, dvo)
 
    return Cmbi, Acci, Dec, Int
 
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def cmdLineTestBench(run='trace', M=1, D=5, R=50, Q=7, Type=None):
    """
    This is the simulation and conversion function for the CIC filter.
 
    Inputs
      run  --  Simulation or coversion type
      M    --  Order of the CIC filter
      D    --  Delay of the Comb Filter
      R    --  Decimation/Interpolation size
      Q    --  Quantization size of input word
    """
    global MaxGain
 
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Parameters / Globals
    MaxGain = D**M        # Max gain of the CIC
    L = 2**(Q)            # Max value for input
    maxV = L * 2*MaxGain  # Max Value for output
    minV = -maxV          # Min Value for output
 
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Signals
    clk = Signal(False)
    rst = Signal(False)
 
    x = Signal(intbv(0, min=-L, max=L))
    y = Signal(intbv(0, min=minV, max=maxV))
 
    dvi = Signal(True)
    dvo = Signal(False)
 
    xcnt  = Signal(0)
    N_CLK = 0
 
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Instantiate MyHDL simulation and coversion functions
    if run == 'trace':
        dut = traceSignals(cic, clk, rst, x, dvi, y, dvo, M, D, R)
    elif run == 'ver':
        toVerilog(cic, clk, rst, x, dvi, y, dvo, M, D, R)
        return None
    elif run == 'vhd':
        toVHDL(cic, clk, rst, x, dvi, y, dvo, M, D, R)
        return None
    else:
        dut = cic(clk, rst, x, dvi, y, dvo, M, D, R)
 
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Stimulus
    @always(delay(1))    
    def clkgen():
        clk.next = not clk
 
    @always(clk.posedge)
    def ist():
 
        # Generate Input samples
        if xcnt >= N_CLK:
            x.next = int(L*uniform(-1,1))
            dvi.next = True
            xcnt.next = 0
        else:
            x.next = 0
            dvi.next = False
            xcnt.next = xcnt + 1
 
 
    @instance
    def stimulus():
        """
        The following is a basic testbench to stimulate the CIC filter
        and create some plots.
        """
 
        ysave = [0.0] * Nfft
        favg  = np.zeros(Nfft)
        xfavg = np.zeros(Nfft)
        xs    = np.zeros(Nfft)
 
        yield clk.posedge
        rst.next = True
        yield delay(10)
        rst.next = False
        yield delay(10)
 
        for ii in range(Nloops):
            for jj in range(Nfft):
                xs[jj] = float(x)/L
                if dvo:
                    if y == 0:
                        #Prevent any log(0) errors, startup zeros
                        ysave[jj] = 10.0**-10
                    else:
                        ysave[jj] = float(y._val)/L  # Undo fix-point
                yield clk.negedge
 
            favg = favg + abs(fft(ysave, Nfft)) / Nfft
            xfavg = xfavg + abs(fft(xs))/Nfft
 
        favg = favg / Nloops
        xfavg = xfavg / Nloops
 
 
        #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # Plot responses
        xa = 2*pi * np.arange(Nfft)/Nfft - pi
        plt.ioff()
        plt.plot(xa, fftshift(20*log10(favg/MaxGain)) )
        plt.plot(xa, fftshift(20*log10(xfavg)) ) 
        plt.title('CIC Filter Frequency Response')
        plt.savefig('plots/myhdl_cic_freq_response_M%d_D%d_R%d.png' % (M,D,R) )
        plt.close('all')
 
        print MaxGain
        xrsp = 20*log10(favg/MaxGain) - 20*log10(xfavg)
        plt.plot(xa, fftshift(xrsp) )
        #plt.plot(xa, fftshift(20*log10(xfavg)) ) 
        plt.title('CIC Filter Frequency Response Gain Removed, Output * 1/D')
        plt.ylabel('Amplitude dB')
        plt.xlabel('Normailzed Frequency radians')
        plt.axis([ -pi, pi, -60, 0])
        plt.savefig('plots/myhdl_cic_freq_response2_M%d_D%d_R%d.png' % (M,D,R) )
        plt.close('all')
 
        # Plot the expected response
        num = np.zeros(D+1)
        num[0] = 1
        num[D] = -1        
        den = [1, -1]
        print num, den
 
        w,H = freqz(num, den)
        Hplt = 20*log10(abs(H[1:]))
        plt.plot(w[1:],  Hplt)
        plt.title('CIC Filter Frequency Response freqz')
        plt.axis([ 0, pi, -60, max(Hplt) + 2])
        plt.ylabel('Amplitude dB')
        plt.xlabel('Normailzed Frequency radians')
        plt.savefig('plots/freqz_cic_freq_response_M%d_D%d.png' % (M,D) )
        plt.close('all')
 
        Hplt = 20*log10(abs(H[1:]/D))
        plt.plot(w[1:],  Hplt)
        plt.title('CIC Filter Frequency Response freqz')
        plt.axis([ 0, pi, -60, max(Hplt) + 2])
        plt.ylabel('Amplitude dB')
        plt.xlabel('Normailzed Frequency radians')
        plt.savefig('plots/freqz_cic_freq_response2_M%d_D%d.png' % (M,D) )
        plt.close('all')
 
        raise StopSimulation
 
    return clkgen, stimulus, ist, dut
 
 
#-------------------------------------------------------------------------------
# Script init
#-------------------------------------------------------------------------------    
if __name__ == "__main__":
 
    if sys.argv[1] == 'ver':
        cmdLineTestBench(sys.argv[1], M=1, D=5, R=5, Q=7, Type='Dec')
        os.system('cp cic.v cic_M1_D5_R5_Q7_DEC.v')
        cmdLineTestBench(sys.argv[1], M=3, D=8, R=8, Q=15, Type='Dec')
        os.system('cp cic.v cic_M3_D8_R8_Q15_DEC.v')
        cmdLineTestBench(sys.argv[1], M=5, D=50, R=50, Q=31, Type='Dec')
        os.system('cp cic.v cic_M5_D50_R50_Q31_DEC.v')
    else:
        tb = cmdLineTestBench(sys.argv[1], M=5, D=5, R=0, Q=7)
        sim = Simulation(tb)
        sim.run()
 
        tb = cmdLineTestBench(sys.argv[1], M=1, D=5, R=5, Q=7, Type='Dec')
        sim = Simulation(tb)
        sim.run() 
 
        tb = cmdLineTestBench(sys.argv[1], M=3, D=8, R=0, Q=15, Type='Dec')
        sim = Simulation(tb)
        sim.run()
 
        tb = cmdLineTestBench(sys.argv[1], M=3, D=8, R=8, Q=15, Type='Dec')
        sim = Simulation(tb)
        sim.run()
 
        tb = cmdLineTestBench(sys.argv[1], M=5, D=50, R=50, Q=31)
        sim = Simulation(tb)
        sim.run()
 
        tb = cmdLineTestBench(sys.argv[1], M=5, D=50, R=50, Q=31)
        sim = Simulation(tb)
        sim.run()
projects/gciccomplete.txt · Last modified: 2008/08/01 12:36 by cfelton
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki