\title{myHDL Two Word Complex Multiplier} \author{Steven K Armour} \maketitle

This notebook/Program is a walkthrough on how to design and construct a two number complex Multiplier unit in myHDL based on the example of Guenter Dannoritzer

Refrances

Guenter Dannoritzer, Complex Math, http://old.myhdl.org/doku.php/projects:cplx_math [3-29-18]

Nonstandard Libraries and tools utilized

myHDL, [myhdlpeek by xesscorp] (using the experimental pandas branch)(https://github.com/xesscorp/myhdlpeek), draw.io


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()

import random

Complex Multiplication Review


In [2]:
A, B=symbols('A, B')
a, b, c, d=symbols('a, b, c, d', real=True)

In [3]:
Multi=A*B; Multi


Out[3]:
$$A B$$

In [4]:
simplify(Multi.subs({A:1+1j, B:1+1j}))


Out[4]:
$$2.0 i$$

In [5]:
Multi=Multi.subs({A:(a+1j*b), B:(c+1j*d)})
Multi


Out[5]:
$$\left(a + 1.0 i b\right) \left(c + 1.0 i d\right)$$

In [6]:
Multi=expand(Multi); Multi


Out[6]:
$$a c + 1.0 i a d + 1.0 i b c - 1.0 b d$$

In [7]:
re(Multi), im(Multi)


Out[7]:
$$\left ( a c - 1.0 b d, \quad 1.0 a d + 1.0 b c\right )$$

Encoding Real and Complex in a Single Input

To encode the real number word and imaginary word into a single word we need to not treat the signal as a number but as a word and then contract the word into a signal word based on a well-posed contraction rule.

The contraction rule for creating a multiplication is that both the real and imaginary part of the whole number is a 2's complement number(word) that we then contract via the first word as $Re$ part and the second word is the $Im$ part such that we then have

$$Re(\text{word})+Im(\text{word})j\Rightarrow Re(\text{word})Im(\text{word})=\mathbb{Z}(\text{word} ) $$

Issue:

There is an ongoing issue with the concat function in myHDL that is ongoing [Issue Reopened 3-29-18] https://github.com/myhdl/myhdl/issues/128#issuecomment-377370353 When that issue is resolved this notebook will be updated accordingly. But for the moment, an attempt to develop this algorithm is shown and the problem with concat is highlighted so this notebook/program can be used as a benchmark for getting concat working properly.


In [8]:
BitWidth=32
WordSize=BitWidth

In [9]:
ReWordLen=WordSize//2; ImWordLen=WordSize//2
print(f'The Re WordLen is {ReWordLen} bits and the Im WordLen is {ImWordLen} bits')


The Re WordLen is 16 bits and the Im WordLen is 16 bits

In [10]:
ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)
ReMax, ReMin, ImMax, ImMin


Out[10]:
$$\left ( 32767, \quad -32768, \quad 32767, \quad -32768\right )$$

Test Tragets


In [11]:
R=(2**ReWordLen)//4; I=(2**ImWordLen)//8
print(f'Re: {R}, Im: {I}')


Re: 16384, Im: 8192

In [12]:
RN=intbv(R, min=ReMin, max=ReMax); RN
RNBin=''.join([str(int(i)) for i in RN])
bin(R, ReWordLen), RNBin, bin(R, ReWordLen)==RNBin


Out[12]:
('0100000000000000', '0100000000000000', True)

In [13]:
IN=intbv(I, min=ImMin, max=ImMax); IN
INBin=''.join([str(int(i)) for i in IN])
bin(I, ImWordLen), INBin, bin(I, ImWordLen)==INBin


Out[13]:
('0010000000000000', '0010000000000000', True)

In [14]:
AN=concat(RN, IN)
ANBin=''.join([str(int(i)) for i in AN])
bin(AN, WordSize), ANBin, bin(AN, WordSize)==ANBin


Out[14]:
('01000000000000000010000000000000', '01000000000000000010000000000000', True)

So now we can then Split AN to get back RN and IN


In [15]:
RNBack=AN[:ReWordLen]; INBack=AN[ImWordLen:]
RNBack, RN, RNBack==RN,INBack, IN, INBack==IN


Out[15]:
(intbv(16384), intbv(16384), True, intbv(8192), intbv(8192), True)

But since myHDL implements 2's complement, we need to test for negative numbers where the leading bit is the signed signal


In [16]:
TestNegNum=-26
print(f"""Target: {TestNegNum}
Absolote Bin: {bin(abs(TestNegNum), 8)}, 
Signed Bin: {bin(TestNegNum, 8)}""")


Target: -26
Absolote Bin: 00011010, 
Signed Bin: 11100110

In [17]:
TestNegNumBV=intbv(TestNegNum)[8:]
TestNegNumBV, TestNegNumBV.signed()


Out[17]:
(intbv(230), intbv(-26))

In [18]:
R=-R; I=-I
print(f'Re: {R}, Im: {I}')


Re: -16384, Im: -8192

In [19]:
RN=intbv(R, min=ReMin, max=ReMax); RN
RNBin=''.join([str(int(i)) for i in RN])
RN.signed(), bin(R, ReWordLen), RNBin, bin(R, ReWordLen)==RNBin


Out[19]:
(intbv(-16384), '1100000000000000', '1100000000000000', True)

In [20]:
IN=intbv(I, min=ImMin, max=ImMax); IN
INBin=''.join([str(int(i)) for i in IN])
IN.signed(), bin(I, ImWordLen), INBin, bin(I, ImWordLen)==INBin


Out[20]:
(intbv(-8192), '1110000000000000', '1110000000000000', True)

! Negative number Issue in MyHDL with concat

At the moment concat does not handle a negative number as its leading term. Due to it setting the returned intbv min to 0


In [21]:
AN=concat(RN, IN).signed()
ANBin=''.join([str(int(i)) for i in AN])
bin(AN, WordSize), ANBin, bin(AN, WordSize)==ANBin 

AN


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-21-597516b84e6e> in <module>()
----> 1 AN=concat(RN, IN).signed()
      2 ANBin=''.join([str(int(i)) for i in AN])
      3 bin(AN, WordSize), ANBin, bin(AN, WordSize)==ANBin
      4 
      5 AN

~/anaconda3/lib/python3.6/site-packages/myhdl/_concat.py in concat(base, *args)
     81 
     82     if basewidth:
---> 83         return intbv(val, _nrbits=basewidth + width)
     84     else:
     85         return intbv(val)

~/anaconda3/lib/python3.6/site-packages/myhdl/_intbv.py in __init__(self, val, min, max, _nrbits)
     58             raise TypeError("intbv constructor arg should be int or string")
     59         self._nrbits = _nrbits
---> 60         self._handleBounds()
     61 
     62     # support for the 'min' and 'max' attribute

~/anaconda3/lib/python3.6/site-packages/myhdl/_intbv.py in _handleBounds(self)
     77             if self._val < self._min:
     78                 raise ValueError("intbv value %s < minimum %s" %
---> 79                                  (self._val, self._min))
     80 
     81     def _hasFullRange(self):

ValueError: intbv value -1073684480 < minimum 0

In [22]:
RNBack=AN[:ReWordLen]; INBack=AN[ImWordLen:]
RNBack.signed(), RN.signed(), RNBack.signed()==RN.signed(), INBack.signed(), IN.signed(), INBack.signed()==IN.signed()


Out[22]:
(intbv(16384), intbv(-16384), False, intbv(8192), intbv(-8192), False)

Algorithm test

Here we prototype the algorithm using myHDL types without explicit HDL type code that will be developed in the final algorithm.

Calc the min/max for the real and imaginary number in 2's complement based on the allowed word size for real and imaginary


In [23]:
ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
ReMax, ReMin


Out[23]:
$$\left ( 32767, \quad -32768\right )$$

In [24]:
ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)
ImMax, ImMin


Out[24]:
$$\left ( 32767, \quad -32768\right )$$

Create a Test A number


In [25]:
AVal=43-78j; AVal


Out[25]:
(43-78j)

Create the $a$ and $b$ part of $A$, concat $a$ and $b$, Confirm that separating $A$ yields the original $a$ and $b$


In [26]:
a=intbv(int(np.real(AVal)), min=ReMin, max=ReMax); a.signed()


Out[26]:
intbv(43)

In [27]:
b=intbv(int(np.imag(AVal)), min=ImMin, max=ImMax); b.signed()


Out[27]:
intbv(-78)

In [28]:
A=concat(a, b); A, A.signed()


Out[28]:
(intbv(2883506), intbv(2883506))

In [29]:
a=intbv(A[:ReWordLen].signed(), min=ReMin, max=ReMax)
b=intbv(A[ImWordLen:].signed(), min=ImMin, max=ReMax)
a, b,


Out[29]:
(intbv(43), intbv(-78))

Perform the same action as above but on $B$


In [30]:
BVal=1+123j; BVal


Out[30]:
(1+123j)

In [31]:
c=intbv(int(np.real(BVal)), min=ReMin, max=ReMax); c


Out[31]:
intbv(1)

In [32]:
d=intbv(int(np.imag(BVal)), min=ImMin, max=ImMax); d


Out[32]:
intbv(123)

In [33]:
B=concat(c, d); B, B.signed()


Out[33]:
(intbv(65659), intbv(65659))

In [34]:
c=intbv(B[:ReWordLen].signed(), min=ReMin, max=ReMax)
d=intbv(B[ImWordLen:].signed(), min=ImMin, max=ImMax)
c, d


Out[34]:
(intbv(1), intbv(123))

Use the separated $a, b, c, d$ from $A, B$ to then find the sup-product of $AB=(ac−bd)+i(ad+bc)$ $$ac, bd \in Re$$ $$ ad, bc \in Im$$


In [35]:
ac=intbv(a*c, min=ReMin, max=ReMax)
np.real(AVal)*np.real(BVal), ac, ac.signed()


Out[35]:
(43.0, intbv(43), intbv(43))

In [36]:
bd=intbv(b.signed()*d.signed(), min=ImMin, max=ImMax)
np.imag(AVal)*np.imag(BVal), bd, bd.signed()


Out[36]:
(-9594.0, intbv(-9594), intbv(-9594))

In [37]:
ad=intbv(a.signed()*d.signed(), min=min(ReMin, ImMin), max=max(ReMax, ImMax))
np.real(AVal)*np.imag(BVal), ad, ad.signed()


Out[37]:
(5289.0, intbv(5289), intbv(5289))

In [38]:
bc=intbv(b.signed()*c.signed(), min=min(ReMin, ImMin), max=max(ReMax, ImMax))
np.imag(AVal)*np.real(BVal), bc, bc.signed()


Out[38]:
(-78.0, intbv(-78), intbv(-78))

Find the difference of the real and the sum of the imaginary products


In [39]:
Re=intbv(ac-bd, min=min(ac.min, bd.min), max=max(ac.max, bd.max))
np.real(AVal)*np.real(BVal)-np.imag(AVal)*np.imag(BVal), Re.signed()


Out[39]:
(9637.0, intbv(9637))

In [40]:
Im=intbv(ad+bc, min=min(ad.min, bc.min), max=max(ad.max, bc.max))
np.real(AVal)*np.imag(BVal)+np.imag(AVal)*np.real(BVal), Im, Im.signed()


Out[40]:
(5211.0, intbv(5211), intbv(5211))

In [41]:
AVal*BVal


Out[41]:
(9637+5211j)

Concat the $Re$ and $Im$ and according to the concatenation rule to a single number


In [42]:
Result=concat(Re, Im)
bin(Re, Re._nrbits)+bin(Im, Im._nrbits), ''.join([str(int(i)) for i in Result])


Out[42]:
('00100101101001010001010001011011', '00100101101001010001010001011011')

myHDL Implementation

Concat issue

The 'concat' is not seeing the inputs as Signal intbv


In [43]:
@block
def CompMulti(A, B, C, ReWordLen=ReWordLen, ImWordLen=ImWordLen):
    """
    Module to implement  the complex multiplication of two complex numbers
    
    Inputs:
        A: A 2's `concat` of the input complex number where
        the input word is a ` concat` according to ReIm
        B: A 2's `concat` of the input complex number where
        input word is a `concat` according to ReIm
    Outputs:
        C: A 2's `concat` of the output  complex number product
        where output world is a `concat` according to ReIm
        
    Conversion Parameters;
        ReWordLen: The word len of the real part of `concat` word
        ImWordLen: The word len of the imag part of `concat` word
    """ 
    #calc the min max of the based on ReWord and ImWord length
    ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
    ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)
    
    #create the regeistors to hold the procuct results
    ac=Signal(intbv(0, min=ReMin, max=ReMax))
    bd=Signal(intbv(0, min=ImMin, max=ImMax))
    ad=Signal(intbv(0, min=min(ReMin, ImMin), max=max(ReMax, ImMax)))
    bc=Signal(intbv(0, min=min(ReMin, ImMin), max=max(ReMax, ImMax)))
    
    @always_comb
    def SepMulti():
        """
        The combinational logic to separate input words into components and 
        find multiplication products
        """
        ac.next=A[:ReWordLen] *B[:ReWordLen]
        bd.next=A[ImWordLen:]*B[ImWordLen:]
        ad.next=A[:ReWordLen]*B[ImWordLen:]
        bc.next=A[ImWordLen:]*B[:ReWordLen]
    
    #will fix when Concat is working properly
    #@always_comb
    #def AddSupConcat():
    #    """
    #    Perfrom the real sup, im addtion, and concat based on
    #    ReIm to final output
    #    """
    #    
    #    C.next=concat(ac-bd, ad+bc)
        
    
    return instances()

Testing

Generate random number within word size bounds for testing


In [44]:
#calc Bounds
Max=(2**(WordSize-1)-1); Min=-2**(WordSize-1)
ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)

#Create Testing Data
Refrance=pd.DataFrame(columns=['a', 'b', 'c', 'd'])
#Generate Testing data and bind values to DF
for i in range(20):
    a=random.sample(range(0, ReMax), 1)[0]
    b=random.sample(range(ImMin, ImMax), 1)[0]
    c=random.sample(range(0, ReMax), 1)[0]
    d=random.sample(range(ImMin, ImMax), 1)[0]
    Refrance.loc[Refrance.shape[0]]=[a, b, c, d]
    
#force the stored value in DF to be ints    
Refrance=Refrance.astype(int)
Refrance


Out[44]:
a b c d
0 3143 -15296 13469 30206
1 10215 14709 21412 17320
2 15744 -12580 26497 -1141
3 30468 4266 6744 21633
4 23561 -25434 15982 -2695
5 19639 -32670 27638 18119
6 6150 4450 27930 30019
7 25268 14297 6706 -28529
8 18273 22261 20847 -25957
9 20020 7935 28408 -6459
10 15802 31674 29960 15397
11 4494 2355 23037 11069
12 12042 -13501 23779 9085
13 16009 -29555 22707 -21916
14 13162 22105 16898 -18823
15 1412 25354 19262 -18327
16 10871 -10812 2943 25673
17 11215 29743 14864 -5931
18 29977 -6786 20900 19193
19 29226 25438 13397 -836

In [45]:
#calc exspected results
RefranceResults=Refrance.copy()
RefranceResults['A']=RefranceResults['a']+1j*RefranceResults['b']
RefranceResults['B']=RefranceResults['c']+1j*RefranceResults['d']
RefranceResults['C']=RefranceResults['A']*RefranceResults['B']
RefranceResults


Out[45]:
a b c d A B C
0 3143 -15296 13469 30206 (3143-15296j) (13469+30206j) (504364043-111084366j)
1 10215 14709 21412 17320 (10215+14709j) (21412+17320j) (-36036300+491872908j)
2 15744 -12580 26497 -1141 (15744-12580j) (26497-1141j) (402814988-351296164j)
3 30468 4266 6744 21633 (30468+4266j) (6744+21633j) (113189814+687884148j)
4 23561 -25434 15982 -2695 (23561-25434j) (15982-2695j) (308007272-469983083j)
5 19639 -32670 27638 18119 (19639-32670j) (27638+18119j) (1134730412-547094419j)
6 6150 4450 27930 30019 (6150+4450j) (27930+30019j) (38184950+308905350j)
7 25268 14297 6706 -28529 (25268+14297j) (6706-28529j) (577326321-624995090j)
8 18273 22261 20847 -25957 (18273+22261j) (20847-25957j) (958766008-10237194j)
9 20020 7935 28408 -6459 (20020+7935j) (28408-6459j) (619980325+96108300j)
10 15802 31674 29960 15397 (15802+31674j) (29960+15397j) (-14256658+1192256434j)
11 4494 2355 23037 11069 (4494+2355j) (23037+11069j) (77460783+103996221j)
12 12042 -13501 23779 9085 (12042-13501j) (23779+9085j) (409003303-211638709j)
13 16009 -29555 22707 -21916 (16009-29555j) (22707-21916j) (-284211017-1021958629j)
14 13162 22105 16898 -18823 (13162+22105j) (16898-18823j) (638493891+125781964j)
15 1412 25354 19262 -18327 (1412+25354j) (19262-18327j) (491860702+462491024j)
16 10871 -10812 2943 25673 (10871-10812j) (2943+25673j) (309569829+247271467j)
17 11215 29743 14864 -5931 (11215+29743j) (14864-5931j) (343105493+375583787j)
18 29977 -6786 20900 19193 (29977-6786j) (20900+19193j) (756762998+433521161j)
19 29226 25438 13397 -836 (29226+25438j) (13397-836j) (412806890+316359950j)

In [46]:
Peeker.clear()
Max=(2**(WordSize-1)-1); Min=-2**(WordSize-1)
ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)

A=Signal(intbv(0, min=Min, max=Max)); Peeker(A, 'A')
B=Signal(intbv(0, min=Min, max=Max)); Peeker(B, 'B')
C=Signal(intbv(0, min=Min, max=Max)); Peeker(C, 'C')
a=Signal(intbv(0, min=ReMin, max=ReMax)); Peeker(a, 'a')
b=Signal(intbv(0, min=ImMin, max=ImMax)); Peeker(b, 'b')
c=Signal(intbv(0, min=ReMin, max=ReMax)); Peeker(c, 'c')
d=Signal(intbv(0, min=ImMin, max=ImMax)); Peeker(d, 'd')

DUT=CompMulti(A, B, C, ReWordLen=ReWordLen, ImWordLen=ImWordLen)

def CompMulti_TB():
    @instance
    def Test():
        for _, j in Refrance.iterrows():
            a.next, b.next, c.next, d.next =j
            print(a, b, c, d)
            #A.next=concat(a, b); B.next=concat(c, d)
            yield delay(1)
        raise StopSimulation

        
    return instances()

In [47]:
sim = Simulation(DUT, CompMulti_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()


0000 0000 0000 0000
0c47 c440 349d 75fe
27e7 3975 53a4 43a8
3d80 cedc 6781 fb8b
7704 10aa 1a58 5481
5c09 9ca6 3e6e f579
4cb7 8062 6bf6 46c7
1806 1162 6d1a 7543
62b4 37d9 1a32 908f
4761 56f5 516f 9a9b
4e34 1eff 6ef8 e6c5
3dba 7bba 7508 3c25
118e 0933 59fd 2b3d
2f0a cb43 5ce3 237d
3e89 8c8d 58b3 aa64
336a 5659 4202 b679
0584 630a 4b3e b869
2a77 d5c4 0b7f 6449
2bcf 742f 3a10 e8d5
7519 e57e 51a4 4af9

Conversion from myHDL to verilog/vhdl


In [48]:
@block
def CompMulti(A, B, C, ReWordLen=ReWordLen, ImWordLen=ImWordLen):
    """
    Module to implent  the complex multibtion of two conplex numbers
    
    Inputs:
        A: A 2's conplimint concat of the input complex number where
        input workd is a concat according to ReIm
        B: A 2's conplimint concat of the input complex number where
        input workd is a concat according to ReIm
    Outputs:
        C: A 2's conplimint concat of the output  complex number product
        where ouput wordd is a concat according to ReIm
        
    Conversion Parmters;
        ReWordLen: The word len of the real part of concat word
        ImWordLen: The word len of the imag part of concat word
    """ 
    #calc the min max of the based on ReWord and ImWord length
    ReMax=(2**(ReWordLen-1)-1); ReMin=-2**(ReWordLen-1)
    ImMax=(2**(ImWordLen-1)-1); ImMin=-2**(ImWordLen-1)
    
    #create the regeistors to hold the procuct results
    ac=Signal(intbv(0, min=ReMin, max=ReMax))
    bd=Signal(intbv(0, min=ImMin, max=ImMax))
    ad=Signal(intbv(0, min=min(ReMin, ImMin), max=max(ReMax, ImMax)))
    bc=Signal(intbv(0, min=min(ReMin, ImMin), max=max(ReMax, ImMax)))
    
    @always_comb
    def SepMulti():
        """
        Compintion logic to sep input words into componets and 
        find multibilication products
        """
        ac.next=A[:ReWordLen] *B[:ReWordLen]
        bd.next=A[ImWordLen:]*B[ImWordLen:]
        ad.next=A[:ReWordLen]*B[ImWordLen:]
        bc.next=A[ImWordLen:]*B[:ReWordLen]
    
    @always_comb
    def AddSupConcat():
        """
        Perfrom the real sup, im addtion, and concat based on
        ReIm to final output
        """
        
        C.next=concat(ac-bd, ad+bc)
        
    
    return instances()

In [49]:
#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 [50]:
A=Signal(intbv(0, min=Min, max=Max))
B=Signal(intbv(0, min=Min, max=Max))
C=Signal(intbv(0, min=Min, max=Max))

In [51]:
DUT=CompMulti(A, B, C, ReWordLen=ReWordLen, ImWordLen=ImWordLen)

!! Concat issue in synthesis


In [52]:
DUT.convert()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-52-9e2b96b2e237> in <module>()
----> 1 DUT.convert()

~/anaconda3/lib/python3.6/site-packages/myhdl/_block.py in convert(self, hdl, **kwargs)
    340         for k, v in conv_attrs.items():
    341             setattr(converter, k, v)
--> 342         return converter(self)
    343 
    344     def config_sim(self, trace=False, **kwargs) :

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py in __call__(self, func, *args, **kwargs)
    175         # print h.top
    176         _checkArgs(arglist)
--> 177         genlist = _analyzeGens(arglist, h.absnames)
    178         siglist, memlist = _analyzeSigs(h.hierarchy)
    179         _annotateTypes(genlist)

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in _analyzeGens(top, absnames)
    168             else:
    169                 v = _AnalyzeAlwaysDecoVisitor(tree, g.senslist)
--> 170             v.visit(tree)
    171         else:  # @instance
    172             f = g.gen.gi_frame

~/anaconda3/lib/python3.6/ast.py in visit(self, node)
    251         method = 'visit_' + node.__class__.__name__
    252         visitor = getattr(self, method, self.generic_visit)
--> 253         return visitor(node)
    254 
    255     def generic_visit(self, node):

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Module(self, node)
   1115 
   1116     def visit_Module(self, node):
-> 1117         _AnalyzeBlockVisitor.visit_Module(self, node)
   1118         if self.tree.kind == _kind.SIMPLE_ALWAYS_COMB:
   1119             for n in self.tree.outputs:

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Module(self, node)
   1066 
   1067     def visit_Module(self, node):
-> 1068         self.generic_visit(node)
   1069         for n in self.tree.outputs:
   1070             s = self.tree.sigdict[n]

~/anaconda3/lib/python3.6/ast.py in generic_visit(self, node)
    259                 for item in value:
    260                     if isinstance(item, AST):
--> 261                         self.visit(item)
    262             elif isinstance(value, AST):
    263                 self.visit(value)

~/anaconda3/lib/python3.6/ast.py in visit(self, node)
    251         method = 'visit_' + node.__class__.__name__
    252         visitor = getattr(self, method, self.generic_visit)
--> 253         return visitor(node)
    254 
    255     def generic_visit(self, node):

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_FunctionDef(self, node)
   1095         self.refStack.push()
   1096         for n in node.body:
-> 1097             self.visit(n)
   1098         self.tree.kind = _kind.SIMPLE_ALWAYS_COMB
   1099         for n in node.body:

~/anaconda3/lib/python3.6/ast.py in visit(self, node)
    251         method = 'visit_' + node.__class__.__name__
    252         visitor = getattr(self, method, self.generic_visit)
--> 253         return visitor(node)
    254 
    255     def generic_visit(self, node):

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Assign(self, node)
    551                 self.tree.vardict[n] = obj
    552         else:
--> 553             self.visit(value)
    554 
    555     def visit_AugAssign(self, node):

~/anaconda3/lib/python3.6/ast.py in visit(self, node)
    251         method = 'visit_' + node.__class__.__name__
    252         visitor = getattr(self, method, self.generic_visit)
--> 253         return visitor(node)
    254 
    255     def generic_visit(self, node):

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Call(self, node)
    583             node.obj = self.getVal(node)
    584         elif f is concat:
--> 585             node.obj = self.getVal(node)
    586         elif f is len:
    587             self.access = _access.UNKNOWN

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_misc.py in getVal(self, node)
    138         expr.col_offset = node.col_offset
    139         c = compile(expr, '<string>', 'eval')
--> 140         val = eval(c, self.tree.symdict, self.tree.vardict)
    141         # val = eval(_unparse(node), self.tree.symdict, self.tree.vardict)
    142         return val

<string> in <module>()

~/anaconda3/lib/python3.6/site-packages/myhdl/_concat.py in concat(base, *args)
     74         else:
     75             raise TypeError("concat: inappropriate argument type: %s"
---> 76                             % type(arg))
     77         if not w:
     78             raise TypeError("concat: arg on pos %d should have length" % (i + 1))

TypeError: concat: inappropriate argument type: <class 'int'>

In [53]:
_=VerilogTextReader('CompMulti', True)


***Verilog modual from CompMulti.v***

 

In [54]:
DUT.convert(hdl='VHDL')


---------------------------------------------------------------------------
ConversionError                           Traceback (most recent call last)
<ipython-input-54-2db9fae1eb2f> in <module>()
----> 1 DUT.convert(hdl='VHDL')

~/anaconda3/lib/python3.6/site-packages/myhdl/_block.py in convert(self, hdl, **kwargs)
    340         for k, v in conv_attrs.items():
    341             setattr(converter, k, v)
--> 342         return converter(self)
    343 
    344     def config_sim(self, trace=False, **kwargs) :

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVHDL.py in __call__(self, func, *args, **kwargs)
    193         arglist = _flatten(h.top)
    194         _checkArgs(arglist)
--> 195         genlist = _analyzeGens(arglist, h.absnames)
    196         siglist, memlist = _analyzeSigs(h.hierarchy, hdl='VHDL')
    197         # print h.top

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in _analyzeGens(top, absnames)
    168             else:
    169                 v = _AnalyzeAlwaysDecoVisitor(tree, g.senslist)
--> 170             v.visit(tree)
    171         else:  # @instance
    172             f = g.gen.gi_frame

~/anaconda3/lib/python3.6/ast.py in visit(self, node)
    251         method = 'visit_' + node.__class__.__name__
    252         visitor = getattr(self, method, self.generic_visit)
--> 253         return visitor(node)
    254 
    255     def generic_visit(self, node):

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Module(self, node)
   1115 
   1116     def visit_Module(self, node):
-> 1117         _AnalyzeBlockVisitor.visit_Module(self, node)
   1118         if self.tree.kind == _kind.SIMPLE_ALWAYS_COMB:
   1119             for n in self.tree.outputs:

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_analyze.py in visit_Module(self, node)
   1070             s = self.tree.sigdict[n]
   1071             if s._driven:
-> 1072                 self.raiseError(node, _error.SigMultipleDriven, n)
   1073             s._driven = "reg"
   1074         for n in self.tree.inputs:

~/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_misc.py in raiseError(self, node, kind, msg)
    146         info = "in file %s, line %s:\n    " % \
    147             (self.tree.sourcefile, self.tree.lineoffset + lineno)
--> 148         raise ConversionError(kind, msg, info)
    149 
    150     def require(self, node, test, msg=""):

ConversionError: in file <ipython-input-48-f950e095a50b>, line 28:
    Signal has multiple drivers: bc

In [55]:
_=VHDLTextReader('CompMulti', True)


***VHDL modual from CompMulti.vhd***