Skip to content

Instantly share code, notes, and snippets.

@cfelton
Last active June 23, 2016 15:57
Show Gist options
  • Save cfelton/595fdf0ca1b8c61264397e37da6d938f to your computer and use it in GitHub Desktop.
Save cfelton/595fdf0ca1b8c61264397e37da6d938f to your computer and use it in GitHub Desktop.
another interface example (gsoc 2016)
from random import randint
import myhdl
from myhdl import Signal, ResetSignal, intbv, always_seq, always_comb
from myhdl import instance, delay, StopSimulation
from myhdl.conversion import verify
try:
from rhea import Signals
except ImportError:
def Signals(dtype, nitems):
return [Signal(dtype) for _ in range(nitems)]
class BlockData(object):
def __init__(self, size=8, drange=10):
"""A parallel interface to a block of data.
This interface encapsulates a block (array) of data that is
accessed in parallel. Typically this flat array of data
represents a N x N matrix where N = sqrt(size). The
data is organized as row::
data[0] = matrix[0, 0]
data[1] = matrix[0, 1]
...
data[8] = matrix[1, 0]
data[9] = matrix[1, 1]
The use of the BlockData interface is not limited to square
matrix, it also can be used for a large set of parallel data.
mucho_data = BlockData(size=128, width=10)
Arguments:
size (int): number of data elements in the parallel
interface.
drange (int, tuple): the data type in the parallel
interface.
Examples:
The 2D-DCT input and outputs, the 2D-DCT takes an single
N x N input and outputs three blocks of the same size. In
this example the block size is assumed 8 x 8::
input_block = BlockData(size=64, drange=(-2000, 2000))
output_blocks = BlockData(size=3*64, drange=(-2000, 2000))
"""
assert isinstance(drange, (int, tuple))
self.size = size
self.drange = drange
if isinstance(drange, int):
dtype = intbv(0)[drange:0]
else:
dtype = intbv(0, min=drange[0], max=drange[1])
self.dtype = dtype
self.data = Signals(dtype, size)
self.data_valid = Signal(bool(0))
def copy(self):
return BlockData(self.size, self.drange)
def get_line_idx(self, lineno, linesize=8):
idxl = lineno * linesize
idxu = idxl + linesize
return idxl, idxu
@myhdl.block
def transform_2d(input_block, output_blocks, clock, reset,
block_size=(8, 8), num_fractional_bits=14):
"""
(arguments == ports)
Arguments:
input_block (BlockData): The input NxN block, where
N == block_size
output_blocks (BlockData): The output blocks
clock (SignalType): system clock
reset (ResetSignal): system reset
Parameters:
block_size (tuple): the input blocks size N x N where
N = block_size
num_fractional_bits (int): The number of
Examples:
In the jpegenc the ...
input_block = BlockData(size=64)
output_blocks = BlockData(size=3*64)
transform_2d(input_block, output_blocks,
"""
assert isinstance(input_block, BlockData)
assert isinstance(output_blocks, BlockData)
ib, ob = input_block, output_blocks
precision = len(ib.data[0])
nitems = block_size[0] * block_size[1]
num_output_blocks = 3 # this is specific to this block
assert len(ib.data) == nitems
assert len(ob.data) == nitems * num_output_blocks
# This is a little silly, doesn't do anything but test the usage
# of creating many instances and list of interfaces during elaboration.
num_lines = block_size[0]
input_copy = BlockData().copy()
lines = [BlockData(size=block_size[1], drange=ib.drange)
for _ in range(num_lines)]
def assign_line(block, line, lineno):
# this overwrites the data reference
idxl, idxu = block.get_line_idx(lineno)
@always_comb
def copy():
# @todo: fix "8"
for ii in range(8):
line.data[ii].next = block.data[idxl+ii]
return copy
insts = []
for ii in range(num_lines):
insts += [assign_line(input_block, lines[ii], ii)]
insts += [transform_1d(lines[ii], input_copy, ii)]
@always_seq(clock.posedge, reset=reset)
def beh_transform():
for nblk in range(num_output_blocks):
if ib.data_valid:
for ii in range(nitems):
blkidx = nblk*64 + ii
ob.data[blkidx].next = ib.data[ii] + (ii-nblk)
return beh_transform
@myhdl.block
def transform_1d(input_line, output_lines, lineno=0):
nitems = len(input_line.data)
offset = nitems * lineno
@always_comb
def blah_copy():
for ii in range(nitems):
output_lines.data[offset+ii].next = input_line.data[ii]
return blah_copy
def verify_conversion():
clock = Signal(bool(0))
reset = ResetSignal(0, active=1, async=False)
ib = BlockData(size=64, drange=(-128, 128))
ob = BlockData(size=3*64, drange=(-128, 128))
rand_input = tuple([randint(-7, 7) for _ in range(64)])
@myhdl.block
def bench():
"""Small wrapper to avoid port conversion
"""
tbdut = transform_2d(ib, ob, clock, reset, block_size=(8, 8))
@instance
def tbclk():
clock.next = False
while True:
yield delay(4)
clock.next = not clock
@instance
def tbstim():
reset.next = reset.active
yield delay(100)
reset.next = not reset.active
yield clock.posedge
for ii in range(64):
ib.data[ii].next = rand_input[ii]
yield clock.posedge
ib.data_valid.next = True
for ii in range(100):
yield clock.posedge
print("%d %d ... %d %d %d" % (
ib.data[0], ib.data[63], ob.data[0], ob.data[64], ob.data[128]))
ib.data_valid.next = False
raise StopSimulation
return tbdut, tbclk, tbstim
inst = bench()
verify.simulator = 'vlog'
inst.verify_convert()
if __name__ == '__main__':
verify_conversion()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment