Skip to content

Instantly share code, notes, and snippets.

@josyb
Created March 15, 2015 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josyb/af6b7809d976b2559ae4 to your computer and use it in GitHub Desktop.
Save josyb/af6b7809d976b2559ae4 to your computer and use it in GitHub Desktop.
List of Constants in MyHDL
'''
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