Re: [myhdl-list] List Of Constants
Brought to you by:
jandecaluwe
From: Henry G. <he...@ca...> - 2015-03-15 18:38:29
|
Hi Josy, Would you mind creating a gist ( https://gist.github.com/ ) of this? I'm struggling to extract the lines from the email (it gets munged at various points) Forgive me if I've missed something, are you trying to do something more involved that a LUT? I'm using lists of bools and ints with an index referencing into them, which convert just fine, though it might not be quite your problem. Cheers, Henry On 15/03/15 17:48, Josy Boelen wrote: > In VHDL we can pass constants in the generic section. > I mimic that in MyHDL by passing constants as the first arguments in the > function call. Until now I have always used singular constants to do > this, but now had the case where a List Of Constants looked more > appealing than writing each one apart. > So I threw in a list an passed that to the function. > The simulation works fine. But the conversion fails depending on the > contents of the list: > * plain ints, intbvs: raise an exception > ```text > myhdl.ConversionError: in file > C:\qdesigns\MyHDL\Source\issues\ListOfConstants\ListOfConstants.py, line > 32: > Object type is not supported in this context: Coeff, <type 'list'> > ``` > * Signals,: the conversion finishes, but the converted code generates > uninitialized signals (wires in Verilog) > ```VHDL > type t_array_components_1_Coeff is array (0 to 2 - 1) of > unsigned(3 downto 0); > signal components_1_Coeff : t_array_components_1_Coeff; > type t_array_components_0_Coeff is array (0 to 2 - 1) of > unsigned(3 downto 0); > signal components_0_Coeff : t_array_components_0_Coeff; > ``` > The workaround was returning to spelling out every constant in the call. > > I distilled a (self-contained this time) example program showing my > intent: > ```python > ''' > Created on 14 Mar 2015 > > @author: Josy > ''' > > > from __future__ import print_function > import os, random > from myhdl import * > > > def flattenlov(D, Q): > ''' a simple utility to turn a list of vectors into a flattened > vector ''' > # in theory, ConcatSignal() would be usable too, > # but that constructs a new Signal, so we would still need > # an @always_comb to assign that newly created Signal to the output > Signal > LNBR_VECTORS = len(D) > LWIDTH_D = len(D[0]) > @always_comb > def flattenlov(): > for i in range(LNBR_VECTORS): > Q.next[(i+1) * LWIDTH_D : i * LWIDTH_D ] = D[i] > return flattenlov > > > def simplefunc( Coeff, Clk, DA, DB, Q): > ''' a simple operation, just for the effect ... ''' > > @always_seq( Clk.posedge, reset = None) > def calc(): > Q.next = Coeff[0] * DA + Coeff[1] * DB > > return calc > > > def loc( NBR_VECTORS, Clk, DA, DB, Q ): > """ > List Of Constants > DA, DB and Q are flattened Lists Of Vectors > """ > > # derive a few constants > LWIDTH_D = len(DA) / NBR_VECTORS > LWIDTH_Q = len(Q) / NBR_VECTORS > LWIDTH_C = LWIDTH_Q - LWIDTH_D > > # must split input data into list Of Vectors > lova = [ DA((i+1) * LWIDTH_D, i * LWIDTH_D) for i in > range(NBR_VECTORS)] > lovb = [ DB((i+1) * LWIDTH_D, i * LWIDTH_D) for i in > range(NBR_VECTORS)] > # we use a List Of Vectors to collect the results too > result = [ Signal( intbv(0)[LWIDTH_Q:]) for _ in range(NBR_VECTORS)] > > # for testing our 'options', we use a local variable for the > coefficients > if USE_COEFF_INT: > # this simulates, but doesn't convert > LCOEFF = COEFF > elif USE_COEFF_INTBV: > # this simulates as well, but doesn't convert either > LCOEFF = [ [intbv(COEFF[i][0])[LWIDTH_C:], intbv(COEFF[i][1]) > [LWIDTH_C:]] for i in range(NBR_VECTORS)] > elif USE_COEFF_SIGNAL: > # this simulates _and_ converts, but the conversion doesn't work > ... > LCOEFF = [ [Signal(intbv(COEFF[i][0])[LWIDTH_C:]), > Signal(intbv(COEFF[i][1])[LWIDTH_C:])] for i in range(NBR_VECTORS)] > > # instantiate as many 'simple functions' as vectors in the input > components = [] > for i in range( NBR_VECTORS ): > components.append( simplefunc(LCOEFF[i], Clk, lova[i], lovb[i], > result[i])) > > # must flatten collected results into the output vector > components.append( flattenlov( result, Q )) > > return components > > > def tb_loc(): > ''' testing ''' > > # helper routines to build/disassemble the flattened in- and out-put > vectors > def flatten( v , w): > ''' flattens a list of integer values > v: list > w: width of element in bits > assume that the values fit in the given bit-width 'w' > ''' > r = 0 > # start with Most Significant Value (or at end of list) > for i in range(len(v)-1,-1,-1): > if v[i] >= 0: > t = v[i] > else: > # negative so use 2's complement number > t = (2**w + v[i]) > # shift previous result 'w' bits left and insert the new set > r = (r << w) + t > return r > > def cut( v, w, n, signed = False): > ''' cut a flattened value up into a list of integers > v: value > w: width of element in bits > n: number of elements > signed: if True: interpret the 'cut w' bits as a 2's > complement representation > ''' > r = [ 0 for _ in range(n)] > for i in range(n): > # mask out the 'w' lowest bits > t = v & (2**w - 1) > if signed: > # test highest bit > if t & 2**(w-1): > #negative, convert 2's complement number > r[i] = t - 2**w > else: > r[i] = t > else: > r[i] = t > # shift input value right by 'w' bits > v >>= w > return r > > > # construct the test data > if not USE_RANDOM: > # use a regular pattern? > tda = [[j + i for i in range(NBR_VECTORS)] for j in > range(NBR_OPS)] > tdb = [[j + i for i in range(NBR_VECTORS-1,-1,-1)] for j in > range(NBR_OPS-1,-1,-1)] > else: > # perhaps random is better ... > random.seed('This gives us repeatable randomness') > tda = [[random.randrange(2**WIDTH_D) for _ in > range(NBR_VECTORS)] for __ in range(NBR_OPS)] > tdb = [[random.randrange(2**WIDTH_D) for _ in range(NBR_VECTORS- > 1,-1,-1)] for __ in range(NBR_OPS-1,-1,-1)] > > print( 'tda: {}'.format( tda)) > print( 'tdb: {}'.format( tdb)) > > # calculate the expected result > print ('expected result:', end = " ") > r = [ [0 for i in range(NBR_VECTORS)] for j in range(NBR_OPS)] > for j in range(NBR_OPS): > for i in range(NBR_VECTORS): > r[j][i] = (tda[j][i] * COEFF[i][0] + tdb[j][i] * COEFF[i] > [1]) > print( r ) > > print('received Q: ', end = ' ') > rq =[None for _ in range(NBR_OPS)] > > dut = loc( NBR_VECTORS, Clk, DA, DB, Q ) > > tCK = 10 > @instance > def clkgen(): > while True: > Clk.next = 1 > yield delay( int( tCK / 2 )) > Clk.next = 0 > yield delay( int( tCK / 2 )) > > @instance > def stimulus(): > DA.next = 0 > DB.next = 0 > yield Clk.posedge > yield delay(int( tCK / 4 )) > for j in range(NBR_OPS): > DA.next = flatten( tda[j], WIDTH_D) > DB.next = flatten( tdb[j], WIDTH_D) > yield Clk.posedge > yield delay(0) > #check the result > rq[j] = cut(int(Q), WIDTH_Q, NBR_VECTORS) > # print( cut(int(Q), WIDTH_Q, NBR_VECTORS), end = ' ' ) # > this doesn't work? > for i in range(NBR_VECTORS): > if rq[j][i] != r[j][i]: > print( 'Failure: j {}, i {} -> received {} != > expected {}'.format( j, i, rq[j][i], r[j][i])) > yield delay(int( tCK / 4 )) > print( rq ) > yield Clk.posedge > raise StopSimulation > > return dut, clkgen, stimulus > > > def convert(): > toVHDL(loc, NBR_VECTORS, Clk, DA, DB, Q ) > toVerilog(loc, NBR_VECTORS, Clk, DA, DB, Q ) > > > if __name__ == '__main__': > def simulate(timesteps, mainclass): > """Runs simulation for MyHDL Class""" > # Remove old .vcd file, otherwise we get a list of renamed .vcd > files lingering about > filename = (mainclass.__name__ +".vcd") > if os.access(filename, os.F_OK): > os.unlink(filename) > > # Run Simulation > tb = traceSignals(mainclass) > sim = Simulation(tb) > sim.run(timesteps) > > NBR_OPS = 8 > NBR_VECTORS = 2 > USE_RANDOM = True > COEFF = [ [i+1,i+2] for i in range(NBR_VECTORS)] > # select how to describe the coefficients > USE_COEFF_INT , USE_COEFF_INTBV , USE_COEFF_SIGNAL = [ False, False, > True] > > WIDTH_D = 8 > WIDTH_C = 4 # >= log2(NBR_VECTORS+2), but keep to multiples of 4, > this makes viewing hex-values in the waveform a lot easier > WIDTH_Q = WIDTH_D + WIDTH_C > > Clk = Signal(bool(0)) > # flattened vectors as input > DA = Signal( intbv()[WIDTH_D * NBR_VECTORS :]) > DB = Signal( intbv()[WIDTH_D * NBR_VECTORS :]) > # and as output > Q = Signal( intbv()[WIDTH_Q * NBR_VECTORS :]) > > simulate( 3000 , tb_loc) > convert() > ``` > I understand that using _ints_ or _intbvs_ doesn't work, as it is not > (yet) supported. But in the case of the _Signals_ am I wrong to expect > _initialised_ signals in the converted code? > > > ------------------------------------------------------------------------------ > Dive into the World of Parallel Programming The Go Parallel Website, sponsored > by Intel and developed in partnership with Slashdot Media, is your hub for all > things parallel software development, from weekly thought leadership blogs to > news, videos, case studies, tutorials and more. Take a look and join the > conversation now. http://goparallel.sourceforge.net/ > _______________________________________________ > myhdl-list mailing list > myh...@li... > https://lists.sourceforge.net/lists/listinfo/myhdl-list |