\title{Floating Point (Q) format and Floating Point Rounding in myHDL} \author{Steven K Armour} \maketitle


In [1]:
from myhdl import *
from myhdlpeek import Peeker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sympy import *
init_printing()

from bitstring import BitArray

#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information myhdl, myhdlpeek, numpy, pandas, matplotlib, sympy, bitstring


Out[1]:
SoftwareVersion
Python3.6.5 64bit [GCC 7.2.0]
IPython6.4.0
OSLinux 4.15.0 30 generic x86_64 with debian buster sid
myhdl0.10
myhdlpeek0.0.7
numpy1.14.3
pandas0.23.0
matplotlib2.2.2
sympy1.1.1
bitstring3.1.5
Sat Aug 25 17:54:05 2018 MDT

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

In [3]:
#4 bit int, 4 bit float
Q=(4,4)
Qlen=Q[0]+Q[1]
Qscale=2**(Q[1]); Qscale


Out[3]:
$$16$$

Postive Addition


In [4]:
a=3.6250; b=4.0625
c=a+b; c


Out[4]:
$$7.6875$$

In [5]:
aQ=int(a*Qscale); bQ=int(b*Qscale)
f'aQ:{aQ}; bA:{bQ}'


Out[5]:
'aQ:58; bA:65'

In [6]:
aQBV=intbv(aQ)[Qlen:]; bQBV=intbv(bQ)[Qlen:]
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'


Out[6]:
'aQBV: 00111010; bQBV: 01000001'

In [7]:
cQ=aQBV+bQBV; cQ


Out[7]:
$$123$$

In [8]:
c==cQ/Qscale


Out[8]:
True

In [9]:
class AddPosTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]; self.Qmax=2**self.Qlen
        self.Qscale=2**self.Q[1]
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndAdd(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1pV2=(self.V1+self.V2).round(decimals=self.Q[1])
        self.V1pV2Q=(self.V1pV2*self.Qscale).astype(int)
        if (self.V1Q+self.V2Q)<self.Qmax:
            self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
            self.bTV=np.append(self.bTV, self.V1); self.bTVQ=np.append(self.bTVQ, self.V1Q).astype(int)
            self.cK=np.append(self.cK, self.V1pV2); self.cKQ=np.append(self.cKQ, self.V1pV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndAdd()
        #print('Done')

In [10]:
@block
def AdderBehaverial(a, b, c):

    @always_comb
    def logic():
        c.next=a+b
        
    return instances()

In [11]:
Peeker.clear()
a=Signal(intbv(0)[Qlen:]); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:]); Peeker(b, 'b')
c=Signal(intbv(0)[Qlen:]); Peeker(c, 'c')

TVG=AddPosTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ


DUT=AdderBehaverial(a, b, c)

def Adder_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):
            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

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

In [12]:
Peeker.to_wavedrom()



In [13]:
PAOData=Peeker.to_dataframe()
#load in the source floating values
PAOData['aTV']=aTV; PAOData['bTV']=bTV
#get the predicted floating Point Sum
PAOData['aTV+bTV']=aTV+bTV
#get the predicted fixed point sum
PAOData['aQ+bQ']=aTVQ+bTVQ
#reorder
PAOData=PAOData[['a', 'aTV', 'b', 'bTV', 'aTV+bTV', 'aQ+bQ',  'c']]
#load the sourced Qed sum
PAOData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
PAOData['cdQ']=PAOData['c']/Qscale
#load the sourced floting sum
PAOData['cKTV']=cKTV
PAOData


Out[13]:
a aTV b bTV aTV+bTV aQ+bQ c cKTVQ cdQ cKTV
0 33 2.0671 33 2.0671 4.1342 66 66 76 4.125 4.7942
1 25 1.5798 25 1.5798 3.1596 50 50 50 3.125 3.1322
2 42 2.6264 42 2.6264 5.2528 84 84 97 5.250 6.0666
3 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
4 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
5 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
6 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
7 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
8 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
9 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
10 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
11 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
12 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
13 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
14 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
15 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
16 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
17 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
18 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
19 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
20 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
21 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
22 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
23 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
24 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
25 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
26 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
27 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
28 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
29 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
... ... ... ... ... ... ... ... ... ... ...
71 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
72 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
73 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
74 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
75 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
76 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
77 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
78 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
79 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
80 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
81 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
82 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
83 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
84 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
85 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
86 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
87 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
88 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
89 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
90 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
91 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
92 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
93 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
94 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
95 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
96 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
97 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
98 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690
99 20 1.2822 20 1.2822 2.5644 40 40 49 2.500 3.1142
100 18 1.1643 18 1.1643 2.3286 36 36 228 2.250 14.2690

101 rows × 10 columns


In [14]:
#dataframe of error measures
PAODataErr=pd.DataFrame()
PAODataErr['aQ+bQ_c']=np.abs(PAOData['aQ+bQ']-PAOData['c'])
PAODataErr['c_cKTVQ']=np.abs(PAOData['c']-PAOData['cKTVQ'])
PAODataErr['cdQ_cKTV']=np.abs(PAOData['cdQ']-PAOData['cKTV'])
PAODataErr['c_cKTVQ__cdQ_cKTV']=np.abs((PAODataErr['c_cKTVQ']/ Qscale)- PAODataErr['cdQ_cKTV'])
PAODataErr


Out[14]:
aQ+bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
0 0 10 0.6692 0.0442
1 0 0 0.0072 0.0072
2 0 13 0.8166 0.0041
3 0 9 0.6142 0.0517
4 0 192 12.0190 0.0190
5 0 9 0.6142 0.0517
6 0 192 12.0190 0.0190
7 0 9 0.6142 0.0517
8 0 192 12.0190 0.0190
9 0 9 0.6142 0.0517
10 0 192 12.0190 0.0190
11 0 9 0.6142 0.0517
12 0 192 12.0190 0.0190
13 0 9 0.6142 0.0517
14 0 192 12.0190 0.0190
15 0 9 0.6142 0.0517
16 0 192 12.0190 0.0190
17 0 9 0.6142 0.0517
18 0 192 12.0190 0.0190
19 0 9 0.6142 0.0517
20 0 192 12.0190 0.0190
21 0 9 0.6142 0.0517
22 0 192 12.0190 0.0190
23 0 9 0.6142 0.0517
24 0 192 12.0190 0.0190
25 0 9 0.6142 0.0517
26 0 192 12.0190 0.0190
27 0 9 0.6142 0.0517
28 0 192 12.0190 0.0190
29 0 9 0.6142 0.0517
... ... ... ... ...
71 0 9 0.6142 0.0517
72 0 192 12.0190 0.0190
73 0 9 0.6142 0.0517
74 0 192 12.0190 0.0190
75 0 9 0.6142 0.0517
76 0 192 12.0190 0.0190
77 0 9 0.6142 0.0517
78 0 192 12.0190 0.0190
79 0 9 0.6142 0.0517
80 0 192 12.0190 0.0190
81 0 9 0.6142 0.0517
82 0 192 12.0190 0.0190
83 0 9 0.6142 0.0517
84 0 192 12.0190 0.0190
85 0 9 0.6142 0.0517
86 0 192 12.0190 0.0190
87 0 9 0.6142 0.0517
88 0 192 12.0190 0.0190
89 0 9 0.6142 0.0517
90 0 192 12.0190 0.0190
91 0 9 0.6142 0.0517
92 0 192 12.0190 0.0190
93 0 9 0.6142 0.0517
94 0 192 12.0190 0.0190
95 0 9 0.6142 0.0517
96 0 192 12.0190 0.0190
97 0 9 0.6142 0.0517
98 0 192 12.0190 0.0190
99 0 9 0.6142 0.0517
100 0 192 12.0190 0.0190

101 rows × 4 columns


In [15]:
PAODataErr.describe()


Out[15]:
aQ+bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
count 101.0 101.000000 101.000000 101.000000
mean 0.0 97.742574 6.143760 0.034850
std 0.0 91.959736 5.732047 0.016739
min 0.0 0.000000 0.007200 0.004100
25% 0.0 9.000000 0.614200 0.019000
50% 0.0 10.000000 0.669200 0.019000
75% 0.0 192.000000 12.019000 0.051700
max 0.0 192.000000 12.019000 0.051700

In [16]:
DUT.convert()
VerilogTextReader('AdderBehaverial');


***Verilog modual from AdderBehaverial.v***

 // File: AdderBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:15 2018


`timescale 1ns/10ps

module AdderBehaverial (
    a,
    b,
    c
);


input [7:0] a;
input [7:0] b;
output [7:0] c;
wire [7:0] c;





assign c = (a + b);

endmodule

Negative Values


In [17]:
a=3.6250; aQ=int(a*Qscale);a, aQ


Out[17]:
$$\left ( 3.625, \quad 58\right )$$

In [18]:
b=-1.5; bMagQ=int(abs(b)*Qscale); bMagQ


Out[18]:
$$24$$

In [19]:
bMagQBV=bin(bMagQ, Qlen); bMagQBV


Out[19]:
'00011000'

In [20]:
bQBVComp="".join([str(int(not(int(i)))) for i in bMagQBV]); bQBVComp


Out[20]:
'11100111'

In [21]:
bQComp=int(bQBVComp, 2); bQComp


Out[21]:
$$231$$

In [22]:
bQ2Comp=bQComp+1; bQ2Comp


Out[22]:
$$232$$

In [23]:
bQBV2Comp=bin(bQ2Comp, 2); bQBV2Comp


Out[23]:
'11101000'

In [24]:
(BitArray(bin=bQBV2Comp).int)/ Qscale


Out[24]:
$$-1.5$$

In [25]:
aQBV=intbv(aQ)[Qlen:].signed()
aQBV, bin(aQBV, Qlen), aQBV.min, aQBV.max


Out[25]:
(intbv(58), '00111010', -128, 128)

In [26]:
bQBV=intbv(int(b*Qscale))[Qlen:].signed()
bQBV, bin(bQBV, Qlen)


Out[26]:
(intbv(-24), '11101000')

In [27]:
bQBV2Comp==bin(bQBV, Qlen)


Out[27]:
True

In [28]:
a+b


Out[28]:
$$2.125$$

In [29]:
c=aQBV+bQBV; c, c/Qscale


Out[29]:
$$\left ( 34, \quad 2.125\right )$$

In [30]:
class AddPosNegTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]
        self.Qmin=-(2**(Qlen-1)); self.Qmax=2**(self.Qlen-1) -1
        self.Qscale=2**self.Q[1]
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.Sign=np.random.randint(2)
        if self.Sign==1:
            self.V2=-self.V2
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndAdd(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1pV2=(self.V1+self.V2).round(decimals=self.Q[1])
        self.V1pV2Q=(self.V1pV2*self.Qscale).astype(int)
        
        check=self.V1Q+self.V2Q
        if self.V1Q>self.Qmin and self.V1Q<self.Qmax:
            if self.V2Q>self.Qmin and self.V2Q<self.Qmax:
                if check>self.Qmin and check<self.Qmax:
                    self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
                    self.bTV=np.append(self.bTV, self.V2); self.bTVQ=np.append(self.bTVQ, self.V1Q).astype(int)
                    self.cK=np.append(self.cK, self.V1pV2); self.cKQ=np.append(self.cKQ, self.V1pV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndAdd()
        #print('Done')

In [31]:
Peeker.clear()
a=Signal(intbv(0)[Qlen:].signed()); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:].signed()); Peeker(b, 'b')
c=Signal(intbv(0)[Qlen:].signed()); Peeker(c, 'c')

TVG=AddPosNegTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ


DUT=AdderBehaverial(a, b, c)

def Adder_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):
            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

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

In [32]:
Peeker.to_wavedrom()



In [33]:
AOData=Peeker.to_dataframe()
#load in the source floating values
AOData['aTV']=aTV; AOData['bTV']=bTV
#get the predicted floating Point Sum
AOData['aTV+bTV']=aTV+bTV
#get the predicted fixed point sum
AOData['aQ+bQ']=aTVQ+bTVQ
#reorder
AOData=AOData[['a', 'aTV', 'b', 'bTV', 'aTV+bTV', 'aQ+bQ',  'c']]
#load the sourced Qed sum
AOData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
AOData['cdQ']=AOData['c']/Qscale
#load the sourced floting sum
AOData['cKTV']=cKTV
AOData


Out[33]:
a aTV b bTV aTV+bTV aQ+bQ c cKTVQ cdQ cKTV
0 20 1.2822 20 1.8320 3.1142 40 40 49 2.500 3.1142
1 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
2 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
3 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
4 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145
5 49 3.0806 49 -1.8052 1.2754 98 98 20 6.125 1.2754
6 23 1.4397 23 -1.1493 0.2904 46 46 4 2.875 0.2904
7 19 1.2206 19 -3.4958 -2.2752 38 38 -36 2.375 -2.2752
8 48 3.0613 48 3.3755 6.4368 96 96 102 6.000 6.4368
9 52 3.2753 52 1.2965 4.5718 104 104 73 6.500 4.5718
10 23 1.4900 23 -2.3142 -0.8242 46 46 -13 2.875 -0.8242
11 37 2.3231 37 -1.3656 0.9575 74 74 15 4.625 0.9575
12 19 1.2145 19 1.2858 2.5003 38 38 40 2.375 2.5003
13 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
14 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
15 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
16 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145
17 49 3.0806 49 -1.8052 1.2754 98 98 20 6.125 1.2754
18 23 1.4397 23 -1.1493 0.2904 46 46 4 2.875 0.2904
19 19 1.2206 19 -3.4958 -2.2752 38 38 -36 2.375 -2.2752
20 48 3.0613 48 3.3755 6.4368 96 96 102 6.000 6.4368
21 52 3.2753 52 1.2965 4.5718 104 104 73 6.500 4.5718
22 23 1.4900 23 -2.3142 -0.8242 46 46 -13 2.875 -0.8242
23 37 2.3231 37 -1.3656 0.9575 74 74 15 4.625 0.9575
24 19 1.2145 19 1.2858 2.5003 38 38 40 2.375 2.5003
25 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
26 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
27 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
28 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145
29 49 3.0806 49 -1.8052 1.2754 98 98 20 6.125 1.2754
... ... ... ... ... ... ... ... ... ... ...
71 37 2.3231 37 -1.3656 0.9575 74 74 15 4.625 0.9575
72 19 1.2145 19 1.2858 2.5003 38 38 40 2.375 2.5003
73 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
74 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
75 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
76 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145
77 49 3.0806 49 -1.8052 1.2754 98 98 20 6.125 1.2754
78 23 1.4397 23 -1.1493 0.2904 46 46 4 2.875 0.2904
79 19 1.2206 19 -3.4958 -2.2752 38 38 -36 2.375 -2.2752
80 48 3.0613 48 3.3755 6.4368 96 96 102 6.000 6.4368
81 52 3.2753 52 1.2965 4.5718 104 104 73 6.500 4.5718
82 23 1.4900 23 -2.3142 -0.8242 46 46 -13 2.875 -0.8242
83 37 2.3231 37 -1.3656 0.9575 74 74 15 4.625 0.9575
84 19 1.2145 19 1.2858 2.5003 38 38 40 2.375 2.5003
85 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
86 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
87 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
88 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145
89 49 3.0806 49 -1.8052 1.2754 98 98 20 6.125 1.2754
90 23 1.4397 23 -1.1493 0.2904 46 46 4 2.875 0.2904
91 19 1.2206 19 -3.4958 -2.2752 38 38 -36 2.375 -2.2752
92 48 3.0613 48 3.3755 6.4368 96 96 102 6.000 6.4368
93 52 3.2753 52 1.2965 4.5718 104 104 73 6.500 4.5718
94 23 1.4900 23 -2.3142 -0.8242 46 46 -13 2.875 -0.8242
95 37 2.3231 37 -1.3656 0.9575 74 74 15 4.625 0.9575
96 19 1.2145 19 1.2858 2.5003 38 38 40 2.375 2.5003
97 38 2.3776 38 -1.5560 0.8216 76 76 13 4.750 0.8216
98 62 3.8753 62 2.6655 6.5408 124 124 104 7.750 6.5408
99 22 1.4366 22 -1.1781 0.2585 44 44 4 2.750 0.2585
100 35 2.2410 35 1.9735 4.2145 70 70 67 4.375 4.2145

101 rows × 10 columns


In [34]:
#dataframe of error measures
AODataErr=pd.DataFrame()
AODataErr['aQ+bQ_c']=np.abs(AOData['aQ+bQ']-AOData['c'])
AODataErr['c_cKTVQ']=np.abs(AOData['c']-AOData['cKTVQ'])
AODataErr['cdQ_cKTV']=np.abs(AOData['cdQ']-AOData['cKTV'])
AODataErr['c_cKTVQ__cdQ_cKTV']=np.abs((AODataErr['c_cKTVQ']/ Qscale)- AODataErr['cdQ_cKTV'])
AODataErr


Out[34]:
aQ+bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
0 0 9 0.6142 0.0517
1 0 63 3.9284 0.0091
2 0 20 1.2092 0.0408
3 0 40 2.4915 0.0085
4 0 3 0.1605 0.0270
5 0 78 4.8496 0.0254
6 0 42 2.5846 0.0404
7 0 74 4.6502 0.0252
8 0 6 0.4368 0.0618
9 0 31 1.9282 0.0093
10 0 59 3.6992 0.0117
11 0 59 3.6675 0.0200
12 0 2 0.1253 0.0003
13 0 63 3.9284 0.0091
14 0 20 1.2092 0.0408
15 0 40 2.4915 0.0085
16 0 3 0.1605 0.0270
17 0 78 4.8496 0.0254
18 0 42 2.5846 0.0404
19 0 74 4.6502 0.0252
20 0 6 0.4368 0.0618
21 0 31 1.9282 0.0093
22 0 59 3.6992 0.0117
23 0 59 3.6675 0.0200
24 0 2 0.1253 0.0003
25 0 63 3.9284 0.0091
26 0 20 1.2092 0.0408
27 0 40 2.4915 0.0085
28 0 3 0.1605 0.0270
29 0 78 4.8496 0.0254
... ... ... ... ...
71 0 59 3.6675 0.0200
72 0 2 0.1253 0.0003
73 0 63 3.9284 0.0091
74 0 20 1.2092 0.0408
75 0 40 2.4915 0.0085
76 0 3 0.1605 0.0270
77 0 78 4.8496 0.0254
78 0 42 2.5846 0.0404
79 0 74 4.6502 0.0252
80 0 6 0.4368 0.0618
81 0 31 1.9282 0.0093
82 0 59 3.6992 0.0117
83 0 59 3.6675 0.0200
84 0 2 0.1253 0.0003
85 0 63 3.9284 0.0091
86 0 20 1.2092 0.0408
87 0 40 2.4915 0.0085
88 0 3 0.1605 0.0270
89 0 78 4.8496 0.0254
90 0 42 2.5846 0.0404
91 0 74 4.6502 0.0252
92 0 6 0.4368 0.0618
93 0 31 1.9282 0.0093
94 0 59 3.6992 0.0117
95 0 59 3.6675 0.0200
96 0 2 0.1253 0.0003
97 0 63 3.9284 0.0091
98 0 20 1.2092 0.0408
99 0 40 2.4915 0.0085
100 0 3 0.1605 0.0270

101 rows × 4 columns


In [35]:
AODataErr.describe()


Out[35]:
aQ+bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
count 101.0 101.000000 101.000000 101.000000
mean 0.0 39.118812 2.438137 0.023496
std 0.0 26.385711 1.646784 0.016939
min 0.0 2.000000 0.125300 0.000300
25% 0.0 9.000000 0.614200 0.009100
50% 0.0 40.000000 2.491500 0.025200
75% 0.0 59.000000 3.699200 0.040400
max 0.0 78.000000 4.849600 0.061800

In [36]:
DUT.convert()
VerilogTextReader('AdderBehaverial');


***Verilog modual from AdderBehaverial.v***

 // File: AdderBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:24 2018


`timescale 1ns/10ps

module AdderBehaverial (
    a,
    b,
    c
);


input signed [7:0] a;
input signed [7:0] b;
output signed [7:0] c;
wire signed [7:0] c;





assign c = (a + b);

endmodule

Multiblication


In [37]:
#Q4.4 *Q4.4 -> Q8.8
Q2=(Q[0]*2, Q[1]*2)
Q2len=Q2[0]+Q2[1]
Q2scale=2**(Q2[1]); Q2scale


Out[37]:
$$256$$

In [38]:
a=3.2500; aQ=int(a*Qscale)
b=-2.065; bQ=int(b*Qscale)
aQ, bQ
bin(aQ, Qlen), bin(bQ, Qlen)


Out[38]:
('00110100', '11011111')

In [39]:
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab


Out[39]:
$$\left ( -6.6875, \quad -6.71125\right )$$

In [40]:
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'


Out[40]:
'aQBV: 00110100; bQBV: 11011111'

In [41]:
abQ=aQBV*bQBV; abQ


Out[41]:
$$-1716$$

In [42]:
abdQ=abQ/ Qscale; abdQ, ab


Out[42]:
$$\left ( -107.25, \quad -6.71125\right )$$

In [43]:
abdQ=abQ/ Q2scale; abdQ,ab


Out[43]:
$$\left ( -6.703125, \quad -6.71125\right )$$

In [44]:
class MultPosNegTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]
        self.Qmin=-(2**(self.Qlen-1)); self.Qmax=2**(self.Qlen-1) -1
        self.Qscale=2**self.Q[1]
        
        #Q4.4 *Q4.4 -> Q8.8
        self.Q2=(self.Q[0]*2, self.Q[1]*2)
        self.Q2len=self.Q2[0]+self.Q2[1]
        self.Q2min=-(2**(self.Q2len-1)); self.Q2max=2**(self.Q2len-1) -1
        self.Q2scale=2**(Q2[1])
        
        
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.Sign=np.random.randint(2)
        if self.Sign==1:
            self.V2=-self.V2
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndMul(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1tV2=(self.V1*self.V2).round(decimals=self.Q2[1])
        self.V1tV2Q=(self.V1tV2*self.Q2scale).astype(int)
        check=self.V1Q*self.V2Q
        if self.V1Q>self.Qmin and self.V1Q<self.Qmax:
            if self.V2Q>self.Qmin and self.V2Q<self.Qmax:
                if check>self.Q2min and check<self.Q2max:
                    self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
                    self.bTV=np.append(self.bTV, self.V2); self.bTVQ=np.append(self.bTVQ, self.V2Q).astype(int)
                    self.cK=np.append(self.cK, self.V1tV2); self.cKQ=np.append(self.cKQ, self.V1tV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndMul()
        #print('Done')

In [45]:
@block
def MultiBehaverial(a, b, c):

    @always_comb
    def logic():
        c.next=a*b
        
    return instances()

In [46]:
Peeker.clear()
a=Signal(intbv(0)[Qlen:].signed()); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:].signed()); Peeker(b, 'b')
c=Signal(intbv(0)[Q2len:].signed()); Peeker(c, 'c')

TVG=MultPosNegTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ

DUT=MultiBehaverial(a, b, c)

def Multi_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):

            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

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

In [47]:
Peeker.to_wavedrom()



In [48]:
MultiData=Peeker.to_dataframe()
#load in the source floating values
MultiData['aTV']=aTV; MultiData['bTV']=bTV
#get the predicted floating Point Sum
MultiData['aTV*bTV']=aTV*bTV
#get the predicted fixed point sum
MultiData['aQ*bQ']=aTVQ*bTVQ
#reorder
MultiData=MultiData[['a', 'aTV', 'b', 'bTV', 'aTV*bTV', 'aQ*bQ',  'c']]
#load the sourced Qed sum
MultiData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
MultiData['cdQ']=MultiData['c']/Q2scale
#load the sourced floting sum
MultiData['cKTV']=cKTV
MultiData


Out[48]:
a aTV b bTV aTV*bTV aQ*bQ c cKTVQ cdQ cKTV
0 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
1 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
2 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
3 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
4 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426
5 23 1.4900 -37 -2.3142 -3.448158 -851 -851 -882 -3.324219 -3.448158
6 37 2.3231 -21 -1.3656 -3.172425 -777 -777 -812 -3.035156 -3.172425
7 19 1.2145 20 1.2858 1.561604 380 380 399 1.484375 1.561604
8 38 2.3776 -24 -1.5560 -3.699546 -912 -912 -947 -3.562500 -3.699546
9 62 3.8753 42 2.6655 10.329612 2604 2604 2644 10.171875 10.329612
10 22 1.4366 -18 -1.1781 -1.692458 -396 -396 -433 -1.546875 -1.692458
11 35 2.2410 31 1.9735 4.422614 1085 1085 1132 4.238281 4.422613
12 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
13 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
14 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
15 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
16 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426
17 23 1.4900 -37 -2.3142 -3.448158 -851 -851 -882 -3.324219 -3.448158
18 37 2.3231 -21 -1.3656 -3.172425 -777 -777 -812 -3.035156 -3.172425
19 19 1.2145 20 1.2858 1.561604 380 380 399 1.484375 1.561604
20 38 2.3776 -24 -1.5560 -3.699546 -912 -912 -947 -3.562500 -3.699546
21 62 3.8753 42 2.6655 10.329612 2604 2604 2644 10.171875 10.329612
22 22 1.4366 -18 -1.1781 -1.692458 -396 -396 -433 -1.546875 -1.692458
23 35 2.2410 31 1.9735 4.422614 1085 1085 1132 4.238281 4.422613
24 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
25 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
26 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
27 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
28 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426
29 23 1.4900 -37 -2.3142 -3.448158 -851 -851 -882 -3.324219 -3.448158
... ... ... ... ... ... ... ... ... ... ...
71 35 2.2410 31 1.9735 4.422614 1085 1085 1132 4.238281 4.422613
72 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
73 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
74 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
75 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
76 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426
77 23 1.4900 -37 -2.3142 -3.448158 -851 -851 -882 -3.324219 -3.448158
78 37 2.3231 -21 -1.3656 -3.172425 -777 -777 -812 -3.035156 -3.172425
79 19 1.2145 20 1.2858 1.561604 380 380 399 1.484375 1.561604
80 38 2.3776 -24 -1.5560 -3.699546 -912 -912 -947 -3.562500 -3.699546
81 62 3.8753 42 2.6655 10.329612 2604 2604 2644 10.171875 10.329612
82 22 1.4366 -18 -1.1781 -1.692458 -396 -396 -433 -1.546875 -1.692458
83 35 2.2410 31 1.9735 4.422614 1085 1085 1132 4.238281 4.422613
84 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
85 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
86 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
87 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
88 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426
89 23 1.4900 -37 -2.3142 -3.448158 -851 -851 -882 -3.324219 -3.448158
90 37 2.3231 -21 -1.3656 -3.172425 -777 -777 -812 -3.035156 -3.172425
91 19 1.2145 20 1.2858 1.561604 380 380 399 1.484375 1.561604
92 38 2.3776 -24 -1.5560 -3.699546 -912 -912 -947 -3.562500 -3.699546
93 62 3.8753 42 2.6655 10.329612 2604 2604 2644 10.171875 10.329612
94 22 1.4366 -18 -1.1781 -1.692458 -396 -396 -433 -1.546875 -1.692458
95 35 2.2410 31 1.9735 4.422614 1085 1085 1132 4.238281 4.422613
96 49 3.0806 -28 -1.8052 -5.561099 -1372 -1372 -1423 -5.359375 -5.561099
97 23 1.4397 -18 -1.1493 -1.654647 -414 -414 -423 -1.617188 -1.654647
98 19 1.2206 -55 -3.4958 -4.266973 -1045 -1045 -1092 -4.082031 -4.266973
99 48 3.0613 54 3.3755 10.333418 2592 2592 2645 10.125000 10.333418
100 52 3.2753 20 1.2965 4.246426 1040 1040 1087 4.062500 4.246426

101 rows × 10 columns


In [49]:
#dataframe of error measures
MultiDataErr=pd.DataFrame()
MultiDataErr['aQ*bQ_c']=np.abs(MultiData['aQ*bQ']-MultiData['c'])
MultiDataErr['c_cKTVQ']=np.abs(MultiData['c']-MultiData['cKTVQ'])
MultiDataErr['cdQ_cKTV']=np.abs(MultiData['cdQ']-MultiData['cKTV'])
MultiDataErr['c_cKTVQ__cdQ_cKTV']=np.abs((MultiDataErr['c_cKTVQ']/ Q2scale)- MultiDataErr['cdQ_cKTV'])
MultiDataErr


Out[49]:
aQ*bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
0 0 51 0.201724 0.002505
1 0 9 0.037460 0.002303
2 0 47 0.184942 0.001348
3 0 53 0.208418 0.001387
4 0 47 0.183926 0.000333
5 0 31 0.123939 0.002845
6 0 35 0.137269 0.000550
7 0 19 0.077229 0.003010
8 0 35 0.137046 0.000327
9 0 40 0.157737 0.001487
10 0 37 0.145583 0.001052
11 0 47 0.184332 0.000738
12 0 51 0.201724 0.002505
13 0 9 0.037460 0.002303
14 0 47 0.184942 0.001348
15 0 53 0.208418 0.001387
16 0 47 0.183926 0.000333
17 0 31 0.123939 0.002845
18 0 35 0.137269 0.000550
19 0 19 0.077229 0.003010
20 0 35 0.137046 0.000327
21 0 40 0.157737 0.001487
22 0 37 0.145583 0.001052
23 0 47 0.184332 0.000738
24 0 51 0.201724 0.002505
25 0 9 0.037460 0.002303
26 0 47 0.184942 0.001348
27 0 53 0.208418 0.001387
28 0 47 0.183926 0.000333
29 0 31 0.123939 0.002845
... ... ... ... ...
71 0 47 0.184332 0.000738
72 0 51 0.201724 0.002505
73 0 9 0.037460 0.002303
74 0 47 0.184942 0.001348
75 0 53 0.208418 0.001387
76 0 47 0.183926 0.000333
77 0 31 0.123939 0.002845
78 0 35 0.137269 0.000550
79 0 19 0.077229 0.003010
80 0 35 0.137046 0.000327
81 0 40 0.157737 0.001487
82 0 37 0.145583 0.001052
83 0 47 0.184332 0.000738
84 0 51 0.201724 0.002505
85 0 9 0.037460 0.002303
86 0 47 0.184942 0.001348
87 0 53 0.208418 0.001387
88 0 47 0.183926 0.000333
89 0 31 0.123939 0.002845
90 0 35 0.137269 0.000550
91 0 19 0.077229 0.003010
92 0 35 0.137046 0.000327
93 0 40 0.157737 0.001487
94 0 37 0.145583 0.001052
95 0 47 0.184332 0.000738
96 0 51 0.201724 0.002505
97 0 9 0.037460 0.002303
98 0 47 0.184942 0.001348
99 0 53 0.208418 0.001387
100 0 47 0.183926 0.000333

101 rows × 4 columns


In [50]:
MultiDataErr.describe()


Out[50]:
aQ*bQ_c c_cKTVQ cdQ_cKTV c_cKTVQ__cdQ_cKTV
count 101.0 101.000000 101.000000 101.000000
mean 0.0 37.772277 0.149043 0.001495
std 0.0 12.915015 0.050054 0.000920
min 0.0 9.000000 0.037460 0.000327
25% 0.0 35.000000 0.137046 0.000738
50% 0.0 40.000000 0.157737 0.001387
75% 0.0 47.000000 0.184942 0.002303
max 0.0 53.000000 0.208418 0.003010

In [51]:
DUT.convert()
VerilogTextReader('MultiBehaverial');


***Verilog modual from MultiBehaverial.v***

 // File: MultiBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:33 2018


`timescale 1ns/10ps

module MultiBehaverial (
    a,
    b,
    c
);


input signed [7:0] a;
input signed [7:0] b;
output signed [15:0] c;
wire signed [15:0] c;





assign c = (a * b);

endmodule

Trunction (Unsighned)


In [52]:
#Q4.4 *Q4.4 -> Q8.8
Q2=(Q[0]*2, Q[1]*2)
Q2len=Q2[0]+Q2[1]
Q2scale=2**(Q2[1]); Q2scale


Out[52]:
$$256$$

In [79]:
a=3.2500; aQ=int(a*Qscale)
b=2.0625; bQ=int(b*Qscale)
aQ, bQ
#bin(aQ, Qlen), bin(bQ, Qlen)


Out[79]:
$$\left ( 52, \quad 33\right )$$

In [54]:
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab


Out[54]:
$$\left ( 6.6875, \quad 6.703125\right )$$

In [55]:
aQBV=intbv(aQ)[Qlen:]; bQBV=intbv(bQ)[Qlen:]
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'


Out[55]:
'aQBV: 00110100; bQBV: 00100001'

In [56]:
abQ=aQBV*bQBV; abQ


Out[56]:
$$1716$$

In [57]:
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))


Out[57]:
(intbv(1716), '11010110100', 11)

In [58]:
for j in range(Q2[1]):
    Trunc=abQBV[Q2len:j]
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))


11010110100 6.703125 0.0
1101011010 6.703125 0.0
110101101 6.703125 0.0
11010110 6.6875 0.015625
1101011 6.6875 0.015625
110101 6.625 0.078125
11010 6.5 0.203125
1101 6.5 0.203125

Trunction (sighned)


In [78]:
a=3.2500; aQ=int(a*Qscale)
b=-2.0625; bQ=int(b*Qscale)
aQ, bQ
#bin(aQ, Qlen), bin(bQ, Qlen)


Out[78]:
$$\left ( 52, \quad -33\right )$$

In [60]:
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab


Out[60]:
$$\left ( -6.6875, \quad -6.703125\right )$$

In [61]:
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'


Out[61]:
'aQBV: 00110100; bQBV: 11011111'

In [62]:
abQ=aQBV*bQBV; abQ


Out[62]:
$$-1716$$

In [63]:
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))


Out[63]:
(intbv(-1716), '100101001100', 12)

In [64]:
for j in range(Q2[1]):
    Trunc=abQBV[Q2len:j].signed()
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))


100101001100 -6.703125 0.0
10010100110 -6.703125 0.0
1001010011 -6.703125 0.0
100101001 -6.71875 0.015625
10010100 -6.75 0.046875
1001010 -6.75 0.046875
100101 -6.75 0.046875
10010 -7.0 0.296875

In [65]:
for j in range(Q2[1]):
    Trunc=(abQBV>>j).signed()
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))


100101001100 -6.703125 0.0
10010100110 -6.703125 0.0
1001010011 -6.703125 0.0
100101001 -6.71875 0.015625
10010100 -6.75 0.046875
1001010 -6.75 0.046875
100101 -6.75 0.046875
10010 -7.0 0.296875

Round Half Up


In [66]:
a=3.2500; aQ=int(a*Qscale)
b=-2.0625; bQ=int(b*Qscale)
aQ, bQ
bin(aQ, Qlen), bin(bQ, Qlen)


Out[66]:
('00110100', '11011111')

In [67]:
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab


Out[67]:
$$\left ( -6.6875, \quad -6.703125\right )$$

In [68]:
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'


Out[68]:
'aQBV: 00110100; bQBV: 11011111'

In [69]:
abQ=aQBV*bQBV; abQ


Out[69]:
$$-1716$$

In [70]:
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))


Out[70]:
(intbv(-1716), '100101001100', 12)

In [71]:
ab, floor(ab+.5), -ceiling(-ab-.5), ceiling(floor(2*ab)/2)


Out[71]:
$$\left ( -6.703125, \quad -7, \quad -7, \quad -7\right )$$

In [72]:
Round=abQBV[Q2len-1:0].signed()
RoundDQ=Round/(2**(Q2[1]))
print(bin(Round), RoundDQ, np.abs(ab-RoundDQ))


100101001100 -6.703125 0.0

{ {(OWID){1'b0}}, 1'b1, {(IWID-OWID-1){1'b0}} }, .5

i_data[(IWID-1):0]+ { {(OWID){1'b0}}, 1'b1, {(IWID-OWID-1){1'b0}} }, x+.5

w_halfup[(IWID-1):(IWID-OWID)], floor(x+.5)


In [73]:
concat(intbv(0)[8:], True, intbv(0)[16-8-1:])


Out[73]:
intbv(128)

In [74]:
PointFive=intbv(int(.5*Q2scale))[16:]; PointFive, bin(PointFive, 16)


Out[74]:
(intbv(128), '0000000010000000')

In [75]:
abQBVP5=intbv(abQBV+PointFive)[16:].signed()
abQBVP5


Out[75]:
intbv(-1588)

In [76]:
abQBVP5=abQBVP5[Q2len-1:Q2len-Qlen].signed(); abQBVP5


Out[76]:
intbv(-7)

In [77]:
abQBVP5, floor(ab+.5)


Out[77]:
(intbv(-7), -7)

Round towards zero


In [ ]:

Round Away from Zero

Round Half to Even


In [ ]: