\title{Digital Arithmetic Cells with myHDL} \author{Steven K Armour} \maketitle

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


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

Compression of Number System Values


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

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


Out[3]:
Decimal Binary hex oct
0 0 000 0x0 0o0
1 1 001 0x1 0o1
2 2 010 0x2 0o2
3 3 011 0x3 0o3
4 4 100 0x4 0o4
5 5 101 0x5 0o5
6 6 110 0x6 0o6
7 7 111 0x7 0o7
8 8 1000 0x8 0o10
9 9 1001 0x9 0o11
10 10 1010 0xa 0o12
11 11 1011 0xb 0o13
12 12 1100 0xc 0o14
13 13 1101 0xd 0o15
14 14 1110 0xe 0o16
15 15 1111 0xf 0o17
16 16 10000 0x10 0o20
17 17 10001 0x11 0o21
18 18 10010 0x12 0o22
19 19 10011 0x13 0o23
20 20 10100 0x14 0o24

Computer Number Systems

Decimal to Binary


In [4]:
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)

Decimal to hex

Decmial to oct

Addition


In [5]:
binarySum=lambda a, b, bits=2: np.binary_repr(a+b, bits)

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


0 + 0 yield 00
0 + 1 yield 01
1 + 0 yield 01
1 + 1 yield 10

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


In [7]:
S_out, C_out=symbols('S_out, C_out')

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


Eq(S_out, Xor(x_1in, x_2in))
Out[8]:
x_1in x_2in S_out
0 0 0 0
1 0 1 1
2 1 0 1
3 1 1 0

In [9]:
CEq=Eq(C_out, x_1in & x_2in)
CEq_TT=TruthTabelGenrator(CEq)
print(CEq)
CEq_TT


Eq(C_out, x_1in & x_2in)
Out[9]:
x_1in x_2in C_out
0 0 0 0
1 0 1 0
2 1 0 0
3 1 1 1

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


Out[10]:
x_1in x_2in S_out C_out
0 0 0 0 0
1 0 1 1 0
2 1 0 1 0
3 1 1 0 1

Passing the carry


In [ ]:


In [11]:
binarySum=lambda a, b, bits=3: np.binary_repr(a+b, bits)

In [12]:
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)}')


0 + 0 yield 000
0 + 1 yield 001
1 + 0 yield 001
1 + 1 yield 010
0 + 2 yield 010
1 + 2 yield 011
2 + 2 yield 100
0 + 3 yield 011
1 + 3 yield 100
2 + 3 yield 101
3 + 3 yield 110

We can see that once exceded the binary repersentation of 2 we have a carry to the next bit


In [13]:
C_in=symbols('C_in')
Sum3Eq=Eq(S_out, x_1in ^x_2in^C_in)
print(Sum3Eq)
SEq_TT=TruthTabelGenrator(Sum3Eq)
SEq_TT


Eq(S_out, Xor(C_in, x_1in, x_2in))
Out[13]:
C_in x_1in x_2in S_out
0 0 0 0 0
1 0 0 1 1
2 0 1 0 1
3 0 1 1 0
4 1 0 0 1
5 1 0 1 0
6 1 1 0 0
7 1 1 1 1

In [14]:
C3Eq=Eq(C_out, (x_1in & x_2in) | ((x_1in & x_2in)& C_in))
CEq_TT=TruthTabelGenrator(C3Eq)
print(CEq)
CEq_TT


Eq(C_out, x_1in & x_2in)
Out[14]:
C_in x_1in x_2in C_out
0 0 0 0 0
1 0 0 1 0
2 0 1 0 0
3 0 1 1 1
4 1 0 0 0
5 1 0 1 0
6 1 1 0 0
7 1 1 1 1

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


Out[15]:
C_in x_1in x_2in S_out C_out
0 0 0 0 0 0
1 0 0 1 1 0
2 0 1 0 1 0
3 0 1 1 0 1
4 1 0 0 1 0
5 1 0 1 0 0
6 1 1 0 0 0
7 1 1 1 1 1

Half Adder


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

In [17]:
#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')


<class 'myhdl.StopSimulation'>: No more events

In [18]:
MakeDFfromPeeker(Peeker.to_wavejson(start_time=0, stop_time=2**len(inputs) -1))


Out[18]:
C_out x_1in x_2in y_out
0 0 0 0 0
1 0 0 1 1
2 0 1 0 1
3 1 1 1 0

In [19]:
toVerilog(HalfAdder, x_1in, x_2in, S_out, C_out)
#toVHDL(And3Gate, x_1in, x_2in, x_3in y_out)
_=VerilogTextReader('HalfAdder')


***Verilog modual from HalfAdder.v***

 // File: HalfAdder.v
// Generated by MyHDL 0.9.0
// Date: Mon Oct  9 19:20:28 2017


`timescale 1ns/10ps

module HalfAdder (
    x_1in,
    x_2in,
    S_out,
    C_out
);


input x_1in;
input x_2in;
output S_out;
wire S_out;
output C_out;
wire C_out;







assign S_out = (x_1in ^ x_2in);
assign C_out = (x_1in & x_2in);

endmodule

Full Adder


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

! need to change the order of the inputs in the simulator so that Cin is last


In [21]:
#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')


<class 'myhdl.StopSimulation'>: No more events

In [22]:
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' ]]


Out[22]:
x_1in x_2in C_in y_out C_out
0 0 0 0 0 0
1 0 0 1 1 0
2 0 1 0 1 0
3 0 1 1 0 1
4 1 0 0 1 0
5 1 0 1 0 1
6 1 1 0 0 1
7 1 1 1 1 1

Ripple Adder

Ripple adders are a exsample of composistion built by using previoues instaninces


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

In [24]:
#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')


<class 'myhdl.StopSimulation'>: No more events

In [25]:
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' ]]


Out[25]:
x_1in x_2in C_in y_out C_out
0 0 0 0 0 0
1 0 0 1 1 0
2 0 1 0 1 0
3 0 1 1 0 1
4 1 0 0 1 0
5 1 0 1 0 1
6 1 1 0 0 1
7 1 1 1 1 1

Ripple Adder using bitvectors

Adder Carry Look Ahead

Adder Behavioral


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

In [27]:
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}')



In [28]:
#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())


Out[28]:
S_out x_1in x_2in
0 = = =
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 = = =
... ... ... ...
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 rows × 3 columns


In [29]:
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')


***Verilog modual from AdderBehavioral.v***

 // File: AdderBehavioral.v
// Generated by MyHDL 0.9.0
// Date: Mon Oct  9 19:20:31 2017


`timescale 1ns/10ps

module AdderBehavioral (
    x_1in,
    x_2in,
    S_out
);


input [2:0] x_1in;
input [2:0] x_2in;
output [3:0] S_out;
wire [3:0] S_out;







assign S_out = (x_1in + x_2in);

endmodule

Suptraction

Two Bit Suptraction (Need to cheeck)


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

In [31]:
#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')


<class 'myhdl.StopSimulation'>: No more events

Suptraction Behavioral


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

In [33]:
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}')



In [34]:
#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())


Out[34]:
S_out x_1in x_2in
0 = = =
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 = = =
... ... ... ...
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 rows × 3 columns


In [35]:
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')


***Verilog modual from SuptractionBehavioral.v***

 // File: SuptractionBehavioral.v
// Generated by MyHDL 0.9.0
// Date: Mon Oct  9 19:20:32 2017


`timescale 1ns/10ps

module SuptractionBehavioral (
    x_1in,
    x_2in,
    S_out
);


input [2:0] x_1in;
input [2:0] x_2in;
output signed [3:0] S_out;
wire signed [3:0] S_out;







assign S_out = (x_1in - x_2in);

endmodule

Multiplication

Multiplication Beahavioral


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

In [37]:
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}')



In [38]:
#got to improve MakeDFfromPeeker to deal with =
MakeDFfromPeeker(Peeker.to_wavejson())


Out[38]:
P_out x_1in x_2in
0 = = =
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 = = =
... ... ... ...
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 rows × 3 columns


In [39]:
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')


***Verilog modual from MultiplyBehavioral.v***

 // File: MultiplyBehavioral.v
// Generated by MyHDL 0.9.0
// Date: Mon Oct  9 19:20:33 2017


`timescale 1ns/10ps

module MultiplyBehavioral (
    x_1in,
    x_2in,
    P_out
);


input [2:0] x_1in;
input [2:0] x_2in;
output [8:0] P_out;
wire [8:0] P_out;







assign P_out = (x_1in * x_2in);

endmodule

Division


In [ ]:

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


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


Out[40]:
$$y{\left (n \right )} = x{\left (n \right )} + y{\left (n - 1 \right )}$$

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


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


Out[41]:
$$Y{\left (z \right )} = X{\left (z \right )} + \frac{1}{z} Y{\left (z \right )}$$

that then yields the Transfer function $H(z)=\dfrac{Y(z)}{X(z)}$


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


Out[42]:
$$\frac{z}{z - 1}$$

the resulting Transfer Function is analyzed by splitting apart the numurator and denomantior to find zeros and poles respectively as well as the coefficient


In [43]:
TFnum, TFden=fraction(TF); TFnum, TFden


Out[43]:
$$\left ( z, \quad z - 1\right )$$

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


Out[44]:
$$\left ( \left [ 1.0\right ], \quad \left [ 1.0, \quad -1.0\right ]\right )$$

these coefinents for the poles and zeros can be pulled into scipy's signals modul for further anylsis via


In [45]:
TFN=sig.TransferFunction(TFnumC, TFdenC, dt=1)
w, mag, phase = sig.dbode(TFN)


** RuntimeWarning: divide by zero encountered in true_divide
** RuntimeWarning: invalid value encountered in true_divide
** RuntimeWarning: invalid value encountered in remainder
** RuntimeWarning: invalid value encountered in greater
** RuntimeWarning: invalid value encountered in less

In [46]:
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')


Out[46]:
<matplotlib.text.Text at 0x1abed764198>

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

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

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

In [50]:
sim=Simulation(DUT, Int_TB(), *Peeker.instances()).run(15)
Peeker.to_wavedrom(tock=True)


<class 'myhdl._SuspendSimulation'>: Simulated 15 timesteps

In [51]:
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')


***Verilog modual from IntCurde.v***

 // File: IntCurde.v
// Generated by MyHDL 0.9.0
// Date: Mon Oct  9 19:20:40 2017


`timescale 1ns/10ps

module IntCurde (
    x_in,
    y_out,
    clk,
    rst
);


input signed [4:0] x_in;
output signed [6:0] y_out;
reg signed [6:0] y_out;
input clk;
input rst;






always @(posedge clk) begin: INTCURDE_LOGIC
    if (rst) begin
        y_out <= 0;
    end
    else begin
        y_out <= (x_in + y_out);
    end
end

endmodule

** ToVerilogWarning: Output port is read internally: y_out