Created
March 15, 2015 19:08
-
-
Save josyb/af6b7809d976b2559ae4 to your computer and use it in GitHub Desktop.
List of Constants in MyHDL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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 a | |
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() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment