\title{myHDL 1Bit $\Delta\Sigma$ Pulse Density Modulated Digital to Analog Converter} \author{Steven K Armour} \maketitle

This is revamp of the Original myHDL $\Delta\Sigma$ DAC Core done by the late George Pantazopoulos

References

@article{cheung_raj_2005, title={Implementation of 12-bit delta-sigma DAC with MSC12xx controller}, volume={Q1}, url={http://www.ti.com/lit/an/slyt076/slyt076.pdf}, journal={Analog Applications Journal}, author={Cheung, Hugo and Raj, Sreeja}, year={2005}, pages={27-32} },

@misc{pantazopoulos_2006, title={DSX1000 ?S DAC Core [MyHDL]}, url={http://old.myhdl.org/doku.php/projects:dsx1000}, author={Pantazopoulos, George}, year={2006} }

Setup

Libraries


In [1]:
from myhdl import *
import pandas as pd
from myhdlpeek import Peeker
import  numpy as np

Helper Function


In [2]:
#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

Architecture Setup


In [3]:
BitWidth=16
#the max in excluded in intbv 
MaxV=int(2**(BitWidth-1)); MinV=-int(2**(BitWidth-1))
a=intbv(0)[BitWidth:]; a=a.signed()
len(a), a.min, MinV, a.max, MaxV


Out[3]:
(16, -32768, -32768, 32768, 32768)

$\Delta$ Difference Section

The Delta ($\Delta$) section takes in the input Digital word $x(n)$ signal and subtracts from the input word the feedback word which is

$$\Delta(n)=x(n)-\begin{cases} 2^{W}-1, & \text{if}\ y(n)=1 \\ 0, & \text{if}\ y(n)=0 \end{cases}$$

where $y(n)$ is the output one bit from the DAC that after leaving the digital device still needs to processed by a Analog low pass filter. And $W$ is the architecture word length. The conversion from the the 1bit output to a word is done by the DigitalRailScaler and the output is feed to the Integrator ($\Sigma$) section.


In [4]:
x1N=np.random.randint(MinV, MaxV, 20)
x2N=np.random.randint(MinV, MaxV, 20)
ResultsDiff=pd.DataFrame(columns=['x1', 'x2', 'yN'])
ResultsDiff['x1']=x1N; ResultsDiff['x2']=x2N
ResultsDiff['yN']=x1N-x2N

ResultsDiff=ResultsDiff[ResultsDiff['yN']>=MinV]
ResultsDiff=ResultsDiff[ResultsDiff['yN']<=MaxV]
ResultsDiff.reset_index(drop=True, inplace=True)
ResultsDiff


Out[4]:
x1 x2 yN
0 3240 11436 -8196
1 -3962 14724 -18686
2 22798 29046 -6248
3 -1816 -23272 21456
4 -27153 -13064 -14089
5 -2138 6168 -8306
6 19407 -10415 29822
7 -22078 -20327 -1751
8 -28618 -19536 -9082
9 14966 16729 -1763
10 7039 -434 7473
11 -5886 314 -6200
12 31833 32342 -509
13 -5716 -23666 17950
14 -10715 -13832 3117
15 -7613 21110 -28723

myHDL Implementation


In [5]:
@block
def Difference(x1, x2, y):
    """
    Prototype Delta Section such that `x1` is th input word, 
    `x2` is the Feedback word and `y` is the ouput to the Sigma Section
    Inputs:
        x1 (2's): The From
        x2 (2's): the suptraction amount
    Outputs:
        y (2's): x1-x2
    """
    @always_comb
    def logic():
        y.next=x1-x2
    return logic

myHDL Testing


In [6]:
Peeker.clear()
x1=Signal(modbv(0, min=MinV, max=MaxV)); Peeker(x1, 'x1')
x2=Signal(modbv(0, min=MinV, max=MaxV)); Peeker(x2, 'x2')
y=Signal(modbv(0, min=MinV, max=MaxV)); Peeker(y, 'y')

DUT=Difference(x1, x2, y)

def Difference_TB():
    for i, Row in ResultsDiff.iterrows():
        x1.next=int(Row['x1']); x2.next=int(Row['x2'])
        yield (delay(1))
    raise StopSimulation
    
sim=Simulation(DUT, Difference_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()



In [7]:
ResultsDiff=pd.merge(ResultsDiff, Peeker.to_dataframe().astype(int, copy=False), how='left')
Comp=(ResultsDiff['yN']==ResultsDiff['y']).all()
print(f'Compersion of Sim and myHDL equal: {Comp}')
ResultsDiff


Compersion of Sim and myHDL equal: True
Out[7]:
x1 x2 yN y
0 3240 11436 -8196 -8196
1 -3962 14724 -18686 -18686
2 22798 29046 -6248 -6248
3 -1816 -23272 21456 21456
4 -27153 -13064 -14089 -14089
5 -2138 6168 -8306 -8306
6 19407 -10415 29822 29822
7 -22078 -20327 -1751 -1751
8 -28618 -19536 -9082 -9082
9 14966 16729 -1763 -1763
10 7039 -434 7473 7473
11 -5886 314 -6200 -6200
12 31833 32342 -509 -509
13 -5716 -23666 17950 17950
14 -10715 -13832 3117 3117
15 -7613 21110 -28723 -28723

myHDL to Verilog


In [8]:
if Comp:
    DUT.convert()
    VerilogTextReader('Difference')


***Verilog modual from Difference.v***

 // File: Difference.v
// Generated by MyHDL 0.10
// Date: Fri Apr 13 05:08:39 2018


`timescale 1ns/10ps

module Difference (
    x1,
    x2,
    y
);
// Prototype Delta Section such that `x1` is th input word, 
// `x2` is the Feedback word and `y` is the ouput to the Sigma Section
// Inputs:
//     x1 (2's): The From
//     x2 (2's): the suptraction amount
// Outputs:
//     y (2's): x1-x2

input signed [15:0] x1;
input signed [15:0] x2;
output signed [15:0] y;
wire signed [15:0] y;





assign y = (x1 - x2);

endmodule

Comparator

The Comparator section performers the same actions as would a Analog Computer does. It takes a input and compares that values to a reference where if the input is greater then the reference then the output is 1 else 0. Thus the Comparator performs a 1Bit quantization of the result of the Integration ($\Sigma$) section.

Mathematically the 1Bit Digital Comparator is

$$y(n)=\begin{cases} 1, & \text{if}\ x>\text{Ref} \\ 0, & \text{otherwise} \end{cases}$$

In [9]:
xN=np.random.randint(MinV, MaxV, 20)
Ref=np.random.randint(MinV, MaxV, 20)
ResultsComp=pd.DataFrame(columns=['x', 'Ref', 'yN'])
ResultsComp['x']=x1N; ResultsComp['Ref']=Ref

for i , Row in ResultsComp.iterrows():
    ResultsComp['yN'].loc[i]=int(Row['x']>Row['Ref'])

ResultsComp


/home/iridium/anaconda3/lib/python3.6/site-packages/pandas/core/indexing.py:194: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._setitem_with_indexer(indexer, value)
Out[9]:
x Ref yN
0 3240 -9254 1
1 -3962 26921 0
2 22798 -27839 1
3 -1816 -9138 1
4 -27153 7551 0
5 -2138 16534 0
6 27608 30326 0
7 19407 -28687 1
8 27713 21241 1
9 -22078 -18480 0
10 -28618 16614 0
11 14966 -20248 1
12 7039 12454 0
13 -5886 -21270 1
14 31833 -16742 1
15 -5716 -4266 0
16 -10715 18835 0
17 -18056 4860 0
18 -7613 16308 0
19 -21225 -11286 0

myHDL Implementation


In [10]:
@block
def Comparator(x, Ref, y):
    """
    Prototype Comparator section used to convert word to binary 
    ouput 
    Inputs:
        x (2's): Input Word
        Ref (2's): Reference to compare too
    
    Outputs:
        y(bool): Outcome of Comparison; True if Input (`x`) is 
        Greater Than the Reference, False Otherwise
    """
    @always_comb
    def logic():
        if x>Ref:
            y.next=1
        else:
            y.next=0
            
    return logic

myHDL Testing


In [11]:
Peeker.clear()
x=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(x, 'x')
Ref=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(Ref, 'Ref')
y=Signal(bool(0)); Peeker(y, 'y')

DUT=Comparator(x, Ref, y)

def Comparator_TB():
    for i, Row in ResultsComp.iterrows():
        x.next=int(Row['x']); Ref.next=int(Row['Ref'])
        yield (delay(1))
    raise StopSimulation
    
sim=Simulation(DUT, Comparator_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()



In [12]:
ResultsComp=pd.merge(ResultsComp, Peeker.to_dataframe().astype(int, copy=False), how='left')
Comp=(ResultsComp['yN']==ResultsComp['y']).all()
print(f'Compersion of Sim and myHDL equal: {Comp}')
ResultsComp


Compersion of Sim and myHDL equal: True
Out[12]:
x Ref yN y
0 3240 -9254 1 1
1 -3962 26921 0 0
2 22798 -27839 1 1
3 -1816 -9138 1 1
4 -27153 7551 0 0
5 -2138 16534 0 0
6 27608 30326 0 0
7 19407 -28687 1 1
8 27713 21241 1 1
9 -22078 -18480 0 0
10 -28618 16614 0 0
11 14966 -20248 1 1
12 7039 12454 0 0
13 -5886 -21270 1 1
14 31833 -16742 1 1
15 -5716 -4266 0 0
16 -10715 18835 0 0
17 -18056 4860 0 0
18 -7613 16308 0 0
19 -21225 -11286 0 0

myHDL to Verilog


In [13]:
if Comp:
    DUT.convert()
    VerilogTextReader('Comparator')


***Verilog modual from Comparator.v***

 // File: Comparator.v
// Generated by MyHDL 0.10
// Date: Fri Apr 13 05:08:41 2018


`timescale 1ns/10ps

module Comparator (
    x,
    Ref,
    y
);
// Prototype Comparator section used to convert word to binary 
// ouput 
// Inputs:
//     x (2's): Input Word
//     Ref (2's): Reference to compare too
// 
// Outputs:
//     y(bool): Outcome of Comparison; True if Input (`x`) is 
//     Greater Than the Reference, False Otherwise

input signed [15:0] x;
input signed [15:0] Ref;
output y;
reg y;




always @(x, Ref) begin: COMPARATOR_LOGIC
    if ((x > Ref)) begin
        y = 1;
    end
    else begin
        y = 0;
    end
end

endmodule

Rail To Rail Digital Scaler

The Rail to Rail Digital Scaler is part of the feedback loop of the $\Delta\Sigma$ DAC where it takes the 1Bit output and converts it to digital word that is feed to the Difference ($\Delta$) Section. Is is called a Rail to Rail since the output range is to constrained to two extremes; where is this is similar to Rail to Rail behavior in Analog Circuits.

The Rail to Rail Digital Scaler can be modeled as $$y(n)=\begin{cases} \text{+Rail} , & \text{if}\ x(n)=1 \\ \text{-Rail}, & \text{if}\ x(n)=0 \end{cases}$$


In [14]:
x=np.random.randint(0, 2, 20)
PRail=MaxV-1; NRail=MinV+1
DigitalRailScaleComp=pd.DataFrame(columns=['x', 'yN'])
DigitalRailScaleComp['x']=x
DigitalRailScaleComp['yN']=[PRail if i is 1 else NRail for i in DigitalRailScaleComp['x']]
DigitalRailScaleComp


Out[14]:
x yN
0 1 32767
1 1 32767
2 0 -32767
3 1 32767
4 1 32767
5 0 -32767
6 0 -32767
7 1 32767
8 0 -32767
9 0 -32767
10 1 32767
11 1 32767
12 1 32767
13 1 32767
14 0 -32767
15 1 32767
16 1 32767
17 0 -32767
18 1 32767
19 1 32767

myHDL Implementation


In [15]:
@block
def DigitalRailScaler(x, y, PRail, NRail):
    """
    Prototype RailToRailDigital Scaler 
    Inputs:
        x (bool): Binary Bit input select scaling
    Ouputs:
        y (2's): the Rail ouput word will be Positive Rail value
        if `x` is the else will be Negative Rail value
    Parms:
        PRail (int): Positive Word Value
        NRail (int): Negative Word Value
    """
    @always_comb
    def logic():
        if x:
            y.next=PRail
        else:
            y.next=NRail
    return logic

myHDL Testing


In [16]:
Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
y=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(y, 'y')

DUT=DigitalRailScaler(x, y, PRail, NRail)
def DigitalRailScaler_TB():
    for i, Row in DigitalRailScaleComp.iterrows():
        x.next=int(Row['x'])
        yield (delay(1))
    raise StopSimulation
    
sim=Simulation(DUT, DigitalRailScaler_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()



In [17]:
SimData=Peeker.to_dataframe().astype(int, copy=False, inplace=True)
DigitalRailScaleComp=DigitalRailScaleComp.loc[SimData.index]
DigitalRailScaleComp=pd.merge(DigitalRailScaleComp, SimData, left_index=True, right_index=True, how='left')
DigitalRailScaleComp.drop('x_y', axis=1, inplace=True)
DigitalRailScaleComp.rename(columns={'x_x':'x'}, inplace=True)

Comp=(DigitalRailScaleComp['yN']==DigitalRailScaleComp['y']).all()
print(f'Compersion of Sim and myHDL equal: {Comp}')
DigitalRailScaleComp


Compersion of Sim and myHDL equal: True
Out[17]:
x yN y
0 1 32767 32767
2 0 -32767 -32767
3 1 32767 32767
5 0 -32767 -32767
7 1 32767 32767
8 0 -32767 -32767
10 1 32767 32767
14 0 -32767 -32767
15 1 32767 32767
17 0 -32767 -32767
18 1 32767 32767

myHDL to Verilog


In [18]:
if Comp:
    DUT.convert()
    VerilogTextReader('DigitalRailScaler')


***Verilog modual from DigitalRailScaler.v***

 // File: DigitalRailScaler.v
// Generated by MyHDL 0.10
// Date: Fri Apr 13 05:08:42 2018


`timescale 1ns/10ps

module DigitalRailScaler (
    x,
    y
);
// Prototype RailToRailDigital Scaler 
// Inputs:
//     x (bool): Binary Bit input select scaling
// Ouputs:
//     y (2's): the Rail ouput word will be Positive Rail value
//     if `x` is the else will be Negative Rail value
// Parms:
//     PRail (int): Positive Word Value
//     NRail (int): Negative Word Value

input x;
output signed [15:0] y;
reg signed [15:0] y;




always @(x) begin: DIGITALRAILSCALER_LOGIC
    if (x) begin
        y = 32767;
    end
    else begin
        y = (-32767);
    end
end

endmodule

$\Sigma$ Integrator

The Integrator ($\Sigma$) section is not a true integrator in the calculus since but instead acts as a accumulator of of the error from the $\Delta$ sections feedback. Where then the accumulated error is feed to the Comparator to convert to a binary value.

In the discrete domain the Integrator is expressed as $$y(n)=y(n-1)+x(n)$$ and in the frequency domain as either $$\dfrac{Y}{X}=\dfrac{1}{1-Z^{-1}}$$ or $$Y=Z^{-1}Y+X$$ where the $z^{-1}$ indicates the use of a D Register to store the past value of $y$


In [19]:
x=np.arange(-11, 13+1)
y=[]
for i, xi in enumerate(x):
    if i==0:
        y.append(0)
    else:
        y.append(y[-1]+xi)

IntegratorComp=pd.DataFrame(columns=['x', 'yN'])
IntegratorComp['x']=x; IntegratorComp['yN']=y
IntegratorComp


Out[19]:
x yN
0 -11 0
1 -10 -10
2 -9 -19
3 -8 -27
4 -7 -34
5 -6 -40
6 -5 -45
7 -4 -49
8 -3 -52
9 -2 -54
10 -1 -55
11 0 -55
12 1 -54
13 2 -52
14 3 -49
15 4 -45
16 5 -40
17 6 -34
18 7 -27
19 8 -19
20 9 -10
21 10 0
22 11 11
23 12 23
24 13 36

myHDL Implementation


In [20]:
@block
def Integrator(x, y, clk, rst):
    '''
        Prototype Simple Integrator/ Accumultor for the Sigma Section
        Inputs:
            x (2's): the x(n) data in feed
            ------------------------
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (2's):  the y(n) output of y(n)=y(n-1)+x(n)
            
    '''
    @always(clk.posedge)
    def logic():
        if rst:
            y.next=0
        else:
            #y(n)=y(n-1)+x(n)
            y.next=y+x
            
    
    return logic

myHDL Testing


In [21]:
Peeker.clear()

x=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(x, 'x')
y=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(y, 'y')

clk, rst=[Signal(bool(0)) for  _ in range(2)]
Peeker(clk, 'clk'); Peeker(rst, 'rst')

DUT=Integrator(x, y, clk, rst)

def Integrator_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        for i, Row in IntegratorComp.iterrows():
            if i==0:
                x.next=0 
            elif i<(IntegratorComp.shape[0]-2):
                x.next=int(Row['x'])
            else:
                x.next=int(Row['x'])
                rst.next=True
            
            yield clk.posedge
        
        raise StopSimulation
                
            
    return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()



In [22]:
SimData=Peeker.to_dataframe()
SimData=SimData.reindex(columns=['x', 'y', 'rst', 'clk'])
SimData


Out[22]:
x y rst clk
0 0 0 0 0
1 -10 0 0 1
2 -10 0 0 0
3 -9 -10 0 1
4 -9 -10 0 0
5 -8 -19 0 1
6 -8 -19 0 0
7 -7 -27 0 1
8 -7 -27 0 0
9 -6 -34 0 1
10 -6 -34 0 0
11 -5 -40 0 1
12 -5 -40 0 0
13 -4 -45 0 1
14 -4 -45 0 0
15 -3 -49 0 1
16 -3 -49 0 0
17 -2 -52 0 1
18 -2 -52 0 0
19 -1 -54 0 1
20 -1 -54 0 0
21 0 -55 0 1
22 0 -55 0 0
23 1 -55 0 1
24 1 -55 0 0
25 2 -54 0 1
26 2 -54 0 0
27 3 -52 0 1
28 3 -52 0 0
29 4 -49 0 1
30 4 -49 0 0
31 5 -45 0 1
32 5 -45 0 0
33 6 -40 0 1
34 6 -40 0 0
35 7 -34 0 1
36 7 -34 0 0
37 8 -27 0 1
38 8 -27 0 0
39 9 -19 0 1
40 9 -19 0 0
41 10 -10 0 1
42 10 -10 0 0
43 11 0 0 1
44 11 0 0 0
45 12 11 1 1
46 12 11 1 0
47 13 0 1 1
48 13 0 1 0

In [23]:
#remove clk and rst 
SimData=SimData[SimData.clk!=0]
SimData=SimData[SimData.rst!=1]
SimData.drop(['clk', 'rst'], axis=1, inplace=True)
SimData.reset_index(drop=True, inplace=True)
SimData.drop([SimData.index[-1]], axis=0, inplace=True)
SimData


Out[23]:
x y
0 -10 0
1 -9 -10
2 -8 -19
3 -7 -27
4 -6 -34
5 -5 -40
6 -4 -45
7 -3 -49
8 -2 -52
9 -1 -54
10 0 -55
11 1 -55
12 2 -54
13 3 -52
14 4 -49
15 5 -45
16 6 -40
17 7 -34
18 8 -27
19 9 -19
20 10 -10

In [24]:
IntegratorComp['x']=IntegratorComp.x.shift(-1)
IntegratorComp=IntegratorComp.loc[SimData.index]
IntegratorComp=IntegratorComp.astype(int, copy=False)
IntegratorComp


Out[24]:
x yN
0 -10 0
1 -9 -10
2 -8 -19
3 -7 -27
4 -6 -34
5 -5 -40
6 -4 -45
7 -3 -49
8 -2 -52
9 -1 -54
10 0 -55
11 1 -55
12 2 -54
13 3 -52
14 4 -49
15 5 -45
16 6 -40
17 7 -34
18 8 -27
19 9 -19
20 10 -10

In [25]:
IntegratorComp=pd.merge(IntegratorComp, SimData,how='left')
Comp=(IntegratorComp['yN']==IntegratorComp['y']).all()
print(f'Compersion of Sim and myHDL equal: {Comp}')
IntegratorComp


Compersion of Sim and myHDL equal: True
Out[25]:
x yN y
0 -10 0 0
1 -9 -10 -10
2 -8 -19 -19
3 -7 -27 -27
4 -6 -34 -34
5 -5 -40 -40
6 -4 -45 -45
7 -3 -49 -49
8 -2 -52 -52
9 -1 -54 -54
10 0 -55 -55
11 1 -55 -55
12 2 -54 -54
13 3 -52 -52
14 4 -49 -49
15 5 -45 -45
16 6 -40 -40
17 7 -34 -34
18 8 -27 -27
19 9 -19 -19
20 10 -10 -10

myHDL to Verilog


In [26]:
if Comp:
    DUT.convert()
    VerilogTextReader('Integrator')


***Verilog modual from Integrator.v***

 // File: Integrator.v
// Generated by MyHDL 0.10
// Date: Fri Apr 13 05:08:44 2018


`timescale 1ns/10ps

module Integrator (
    x,
    y,
    clk,
    rst
);
// Prototype Simple Integrator/ Accumultor for the Sigma Section
// Inputs:
//     x (2's): the x(n) data in feed
//     ------------------------
//     
//     clk(bool): clock feed
//     rst(bool): reset feed
// 
// Outputs:
//     y (2's):  the y(n) output of y(n)=y(n-1)+x(n)
//     

input signed [15:0] x;
output signed [15:0] y;
reg signed [15:0] y;
input clk;
input rst;




always @(posedge clk) begin: INTEGRATOR_LOGIC
    if (rst) begin
        y <= 0;
    end
    else begin
        y <= (y + x);
    end
end

endmodule

/home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:296: ToVerilogWarning: Output port is read internally: y
  category=ToVerilogWarning

1Bit $\Delta\Sigma$-DAC

The final topology of the 1Bit $\Delta\Sigma$-DAC is shown in it's block diagram where the section that where developed above are are stitched via the following

The Delta Section, which consists the DAC input and the feedback subtraction after the binary output is converted to the feed back word performs the following

$$\Delta(n)=x(n)-\begin{cases} 2^{W}-1, & \text{if}\ y(n)=1 \\ 0, & \text{if}\ y(n)=0 \end{cases}$$

The Sigma section is the error integrator performing (note: $\Sigma(n)$ is a variable and not summation from calculus) $$\Sigma(n+1)=\Sigma(n)+\Delta(n)$$

The Comparator converts the output error to a binary output based on wither the sight of the $\Sigma$ sections accumulated error is positive or negative where in this case 0 is defined to be negative resulting in

$$y(n)=\begin{cases} 1, & \text{if}\ \Sigma(n)>0 \\ 0, & \text{otherwise} \end{cases}$$

In [27]:
TestData=pd.DataFrame(columns=['Ref', 'QRef'])
refvals = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

# Generate the actual DAC codes based on the DAC resolution
dac_codes = list()

for value in refvals:

    dac_code = int(value * 2**(BitWidth-2))

    if dac_code == 2**BitWidth:
        dac_code = 2**BitWidth-1
    elif dac_code > 2**BitWidth:
        raise Exception

    dac_codes.append(dac_code)
TestData['Ref']=refvals; TestData['QRef']=dac_codes
TestData


Out[27]:
Ref QRef
0 0.0 0
1 0.1 1638
2 0.2 3276
3 0.3 4915
4 0.4 6553
5 0.5 8192
6 0.6 9830
7 0.7 11468
8 0.8 13107
9 0.9 14745
10 1.0 16384

In [28]:
class DACSim:
    def __init__(self):
        self.yStore=[]
        self.FB=0
        self.Sigma=0
    
    def Action(self, x):
        self.DeltaAction(x, self.FB)
        self.SigmaAction(self.Delta)
        self.CompAction(self.Sigma)
        self.yStore.append(self.y)
        self.FBScale(self.y)
        
    def DeltaAction(self, x, FB):
        self.Delta=x-FB
    
    def SigmaAction(self, Delta):
        self.Sigma=self.Sigma+Delta
    
    def CompAction(self, Sigma):
        if Sigma>0:
            self.y=1
        else:
            self.y=0
    
    def FBScale(self, y):
        Scale=2**BitWidth-1
        if y==1:
            self.FB=Scale
        else:
            self.FB=0

In [29]:
DAC=DACSim()
DAC.Action(0)
print(f'x: {0}, Delta: {DAC.Delta}, Sigma: {DAC.Sigma}, y: {DAC.y}, FB: {DAC.FB}')

for i in TestData['QRef']:
    DAC.Action(i)
    print(f'x: {i}, Delta: {DAC.Delta}, Sigma: {DAC.Sigma}, y: {DAC.y}, FB: {DAC.FB}')


x: 0, Delta: 0, Sigma: 0, y: 0, FB: 0
x: 0, Delta: 0, Sigma: 0, y: 0, FB: 0
x: 1638, Delta: 1638, Sigma: 1638, y: 1, FB: 65535
x: 3276, Delta: -62259, Sigma: -60621, y: 0, FB: 0
x: 4915, Delta: 4915, Sigma: -55706, y: 0, FB: 0
x: 6553, Delta: 6553, Sigma: -49153, y: 0, FB: 0
x: 8192, Delta: 8192, Sigma: -40961, y: 0, FB: 0
x: 9830, Delta: 9830, Sigma: -31131, y: 0, FB: 0
x: 11468, Delta: 11468, Sigma: -19663, y: 0, FB: 0
x: 13107, Delta: 13107, Sigma: -6556, y: 0, FB: 0
x: 14745, Delta: 14745, Sigma: 8189, y: 1, FB: 65535
x: 16384, Delta: -49151, Sigma: -40962, y: 0, FB: 0

myHDL Implementation


In [30]:
@block
def DAC_1Bit(x, y, clk, rst):
    """
    A 1bit SigmaDelta DAC based on 
    http://old.myhdl.org/doku.php/projects:dsx1000
    using a Instantiation  approach
    Inputs:
        x (2's): Input Digital word to be translated to PDM ouput
        -----------------------------
        clk (bool): system clock input
        rst (bool); reset signal
    Ouput:
        y (bool): the 1BIt Sigma Delta PDM output 
    """
    #Internal Parameter Calculations; Dont show up in conversion
    #Though values are set to the various subcomponets in the
    #Conversion
    
    RES = len(x)
 
    DREF_NEG =  0
    DREF_POS =  (2**RES)-1
 
    MIN = -2**(RES-1)
    MAX = +2**(RES-1)
    
    #Buss and Wires
    #Comparter Ref: 0
    Ref=Signal(intbv(0)[RES:])
    #bus from the Delta Section to the Sigma Section
    diff_o  = Signal(intbv(0, min=4*MIN, max=4*MAX))
    #But from the Sigma Section to the Comparator
    Intgral_o   = Signal(intbv(0, min=4*MIN, max=4*MAX))
    #Wire from Compater to synchronized output
    comp_o  = Signal(bool(0))
    #bus feedback from the DigitalRailScaler to the Delta Section
    ddc_o   = Signal(intbv(0, min=4*MIN, max=4*MAX))
    
    
    # Delta
    Diff=Difference(x, ddc_o, diff_o)
    #Sigma
    Intgrat=Integrator(diff_o, Intgral_o,clk, rst)
    #Comparator agenst 0
    Comp=Comparator(Intgral_o, Ref, comp_o)
    #Digital Scale for FB: Scale is (2**RES)-1:0
    DDC=DigitalRailScaler(comp_o, ddc_o, DREF_POS, DREF_NEG)
    
    #create synchronized ouput
    @always(clk.posedge)
    def Ouput():
        if rst:
            y.next=0
        else:
            y.next=comp_o
    
    return instances()

myHDL Testing


In [31]:
Peeker.clear()
clk, rst=[Signal(bool(0)) for i in range(2)]
Peeker(clk, 'clk'); Peeker(rst, 'rst')

x=Signal(intbv(0, min=MinV, max=MaxV)); Peeker(x, 'x')
y=Signal(bool(0)); Peeker(y, 'y')

DUT=DAC_1Bit(x, y, clk, rst)

def DAC_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    
    @instance
    def Stimules():
        for i, Row in TestData.iterrows():
            x.next=int(Row['QRef'])
            yield clk.posedge
            
        raise StopSimulation
    
    return instances()
        
        

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



In [32]:
SimData=Peeker.to_dataframe()
SimData=SimData[SimData.clk!=0]
SimData.drop(['clk', 'rst'], axis=1, inplace=True)
SimData.reset_index(drop=True, inplace=True)
SimData


Out[32]:
x y
0 1638 0
1 3276 0
2 4915 1
3 6553 0
4 8192 0
5 9830 0
6 11468 0
7 13107 0
8 14745 0
9 16384 0

myHDL to Verilog


In [33]:
DUT.convert()
VerilogTextReader('DAC_1Bit');


***Verilog modual from DAC_1Bit.v***

 // File: DAC_1Bit.v
// Generated by MyHDL 0.10
// Date: Fri Apr 13 05:08:45 2018


`timescale 1ns/10ps

module DAC_1Bit (
    x,
    y,
    clk,
    rst
);
// A 1bit SigmaDelta DAC based on 
// http://old.myhdl.org/doku.php/projects:dsx1000
// using a Instantiation  approach
// Inputs:
//     x (2's): Input Digital word to be translated to PDM ouput
//     -----------------------------
//     clk (bool): system clock input
//     rst (bool); reset signal
// Ouput:
//     y (bool): the 1BIt Sigma Delta PDM output 

input signed [15:0] x;
output y;
reg y;
input clk;
input rst;

wire [15:0] Ref;
reg signed [17:0] ddc_o;
reg signed [17:0] Intgral_o;
wire signed [17:0] diff_o;
reg comp_o;

assign Ref = 16'd0;



assign diff_o = (x - ddc_o);


always @(posedge clk) begin: DAC_1BIT_INTEGRATOR0_0_LOGIC
    if (rst) begin
        Intgral_o <= 0;
    end
    else begin
        Intgral_o <= (Intgral_o + diff_o);
    end
end


always @(Intgral_o, Ref) begin: DAC_1BIT_COMPARATOR0_0_LOGIC
    if ((Intgral_o > $signed({1'b0, Ref}))) begin
        comp_o = 1;
    end
    else begin
        comp_o = 0;
    end
end


always @(comp_o) begin: DAC_1BIT_DIGITALRAILSCALER0_0_LOGIC
    if (comp_o) begin
        ddc_o = 65535;
    end
    else begin
        ddc_o = 0;
    end
end


always @(posedge clk) begin: DAC_1BIT_OUPUT
    if (rst) begin
        y <= 0;
    end
    else begin
        y <= comp_o;
    end
end

endmodule

/home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: Ref
  category=ToVerilogWarning