Skip to content

Commit

Permalink
[pymtl.tools.transl] add hacky support for nested indexing, #137
Browse files Browse the repository at this point in the history
  • Loading branch information
dmlockhart committed May 13, 2015
1 parent 6bd58bc commit 45c8a1d
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 50 deletions.
60 changes: 46 additions & 14 deletions pymtl/tools/simulation/SimulationTool_transl_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,66 +1164,66 @@ def logic():
assert m.b[1] == a[1]

#-----------------------------------------------------------------------
# translation_issue_136_b
# translation_issue_88_b
#-----------------------------------------------------------------------
def test_translation_issue_136_b( setup_sim ):
def test_translation_issue_88_b( setup_sim ):

class TestTranslationIssue136_Bchild( Model ):
class TestTranslationIssue88_Bchild( Model ):
def __init__( s ):
s.in_ = InPort ( 4 )
s.out = OutPort( 4 )
@s.combinational
def logic():
s.out.value = s.in_.value

class TestTranslationIssue136_B( Model ):
class TestTranslationIssue88_B( Model ):
def __init__( s ):
s.in_ = InPort [ 1 ]( 4 )
s.out = OutPort[ 1 ]( 4 )
s.isub = TestTranslationIssue136_Bchild[1]()
s.osub = TestTranslationIssue136_Bchild[1]()
s.isub = TestTranslationIssue88_Bchild[1]()
s.osub = TestTranslationIssue88_Bchild[1]()
s.connect( s.in_[0], s.isub[0].in_ )
s.connect( s.out[0], s.osub[0].out )
@s.combinational
def logic():
for i in range(4):
s.osub[0].in_[i].value = s.isub[0].out[i] and s.isub[0].out[i]

m, sim = setup_sim( TestTranslationIssue136_B() )
m, sim = setup_sim( TestTranslationIssue88_B() )
for i in range(10):
a = randrange(2**4)
m.in_[0].value = a
sim.cycle()
assert m.out[0] == a

#-----------------------------------------------------------------------
# translation_issue_136_c
# translation_issue_88_c
#-----------------------------------------------------------------------
def test_translation_issue_136_c( setup_sim ):
def test_translation_issue_88_c( setup_sim ):

class TestTranslationIssue136_Cchild( Model ):
class TestTranslationIssue88_Cchild( Model ):
def __init__( s ):
s.in_ = InPort ( 4 )
s.out = OutPort( 4 )
@s.combinational
def logic():
s.out.value = s.in_.value

class TestTranslationIssue136_C( Model ):
class TestTranslationIssue88_C( Model ):
def __init__( s ):
s.in_ = InPort [ 1 ]( 4 )
s.val = InPort [ 4 ]( 1 )
s.out = OutPort[ 1 ]( 4 )
s.isub = TestTranslationIssue136_Cchild[1]()
s.osub = TestTranslationIssue136_Cchild[1]()
s.isub = TestTranslationIssue88_Cchild[1]()
s.osub = TestTranslationIssue88_Cchild[1]()
s.connect( s.in_[0], s.isub[0].in_ )
s.connect( s.out[0], s.osub[0].out )
@s.combinational
def logic():
for i in range(4):
s.osub[0].in_[i].value = s.val[i] and s.isub[0].out[i]

m, sim = setup_sim( TestTranslationIssue136_C() )
m, sim = setup_sim( TestTranslationIssue88_C() )
for j in range(4):
m.val[j].value = 1
for i in range(10):
Expand All @@ -1232,6 +1232,38 @@ def logic():
sim.cycle()
assert m.out[0] == a

#-----------------------------------------------------------------------
# translation_issue_88_d
#-----------------------------------------------------------------------
def test_translation_issue_88_d( setup_sim ):

class TestTranslationIssue88_Dchild( Model ):
def __init__( s ):
s.in_ = InPort [1]( 4 )
s.out = OutPort[1]( 4 )
@s.combinational
def logic():
s.out[0].value = s.in_[0]

class TestTranslationIssue88_D( Model ):
def __init__( s ):
s.in_ = InPort [ 1 ]( 4 )
s.out = OutPort[ 1 ]( 4 )
s.isub = TestTranslationIssue88_Dchild[1]()
s.osub = TestTranslationIssue88_Dchild[1]()
s.connect( s.in_[0], s.isub[0].in_[0] )
s.connect( s.out[0], s.osub[0].out[0] )
@s.combinational
def logic():
s.osub[0].in_[0].value = s.isub[0].out[0]

m, sim = setup_sim( TestTranslationIssue88_D() )
for i in range(10):
a = randrange(2**4)
m.in_[0].value = a
sim.cycle()
assert m.out[0] == a


#'TODO: negative indexes: my_signal[-2] issue #31
#'TODO: negative indexes: my_signal[0:-2] issue #31
Expand Down
120 changes: 88 additions & 32 deletions pymtl/tools/translation/verilog_structural.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import sys
import collections

from ...model.signals import InPort, OutPort, Constant
from ...model.signals import Signal, InPort, OutPort, Wire, Constant
from ...model.signal_lists import PortList, WireList
from exceptions import VerilogTranslationError

#-----------------------------------------------------------------------
# header
Expand Down Expand Up @@ -294,38 +296,92 @@ def create_declarations( model, regs, ints, params, arrays ):
#-----------------------------------------------------------------------
# array_declarations
#-----------------------------------------------------------------------
# TODO: clean this up!
def array_declarations( model, symtab ):

arrays = symtab[-1]
scode = ''

# Print the array declarations
if arrays:
arrays = sorted( arrays, key=lambda x: x.name )
scode += ' // array declarations\n'
for ports in arrays:

first = ports[0]

# Output Port
if ports.is_lhs:
scode += ' reg [{:4}:0] {}[0:{}];\n'.format(
first.nbits-1, ports.name, len(ports)-1)
for i, port in enumerate(ports):
scode += ' assign {0} = {1}[{2:3}];\n'.format(
signal_to_str( port, None, model ), ports.name, i )

# Input Port
else:
scode += ' wire [{:4}:0] {}[0:{}];\n'.format(
first.nbits-1, ports.name, len(ports)-1)
for i, port in enumerate(ports):
scode += ' assign {1}[{2:3}] = {0};\n'.format(
signal_to_str( port, None, model ), ports.name, i )

scode += '\n'

return scode
if not symtab[-1]:
return '\n'

#---------------------------------------------------------------------
# helper to generate arrays to output port assignments
#---------------------------------------------------------------------
def _gen_array_to_output( ports ):
if isinstance( ports[0], (Wire,InPort,OutPort) ):
stmts = ' reg [{:4}:0] {}[0:{}];\n' \
.format(ports[0].nbits-1, ports.name, len(ports)-1)
for i, port in enumerate(ports):
stmts += ' assign {0} = {1}[{2:3}];\n' \
.format(signal_to_str(port, None, model), ports.name, i)

elif isinstance( ports[0], (PortList,WireList) ):
if not isinstance( ports[0][0], (Wire,InPort,OutPort) ):
raise VerilogTranslationError(
'Port lists with more than 2 dimenstions are not supported!'
)
stmts = ' reg [{bw:4}:0] {name}[0:{sz0}][0:{sz1}];\n' \
.format( bw = ports[0][0].nbits-1,
name = ports.name,
sz0 = len(ports)-1,
sz1 = len(ports[0])-1 )
for i, plist in enumerate(ports):
for j, port in enumerate(plist):
stmts += ' assign {0} = {1}[{2:3}][{3:3}];\n' \
.format(signal_to_str(port, None, model),
ports.name, i, j)

else:
raise VerilogTranslationError(
'An internal error occured when translating array accesses!\n'
'Expected a list of Wires or Ports, instead got: {}'
.format( type(ports[0]) )
)

return stmts

#---------------------------------------------------------------------
# helper to generate input port to array assignments
#---------------------------------------------------------------------
def _gen_input_to_array( ports ):
if isinstance( ports[0], (Wire,InPort,OutPort) ):
stmts = ' wire [{:4}:0] {}[0:{}];\n' \
.format(ports[0].nbits-1, ports.name, len(ports)-1)
for i, port in enumerate(ports):
stmts += ' assign {1}[{2:3}] = {0};\n' \
.format(signal_to_str(port, None, model), ports.name, i)

elif isinstance( ports[0], (PortList,WireList) ):
if not isinstance( ports[0][0], (Wire,InPort,OutPort) ):
raise VerilogTranslationError(
'Port lists with more than 2 dimenstions are not supported!'
)
stmts = ' wire [{bw:4}:0] {name}[0:{sz0}][0:{sz1}];\n' \
.format( bw = ports[0][0].nbits-1,
name = ports.name,
sz0 = len(ports)-1,
sz1 = len(ports[0])-1 )
for i, plist in enumerate(ports):
for j, port in enumerate(plist):
stmts += ' assign {1}[{2:3}][{3:3}] = {0};\n' \
.format(signal_to_str(port, None, model),
ports.name, i, j)

else:
raise VerilogTranslationError(
'An internal error occured when translating array accesses!\n'
'Expected a list of Wires or Ports, instead got: {}'
.format( type(ports[0]) )
)
return stmts

#---------------------------------------------------------------------
# print the array declarations
#---------------------------------------------------------------------
arrays = sorted( symtab[-1], key=lambda x: x.name )
scode = ' // array declarations\n'

for ports in arrays:
if ports.is_lhs: scode += _gen_array_to_output( ports )
else: scode += _gen_input_to_array ( ports )

return scode + '\n'


12 changes: 8 additions & 4 deletions pymtl/tools/translation/visitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ def visit_Name( self, node ):
#-------------------------------------------------------------------------
# PortListNameHack
#-------------------------------------------------------------------------
# Temporary hack to handle cases where
# Temporary hack to handle cases where port lists are named improperly.
class PortListNameHack( ast.NodeTransformer ):

def __init__( self, model ):
Expand All @@ -739,18 +739,18 @@ def visit_Subscript( self, node ):
# if the PortList parent is not the same as the current modules parent, but
# there is no '$' in the name, it's been named improperly! fix it!

if plist[0].parent != self.model and not '$' in plist.name:
if plist.parent != self.model and not '$' in plist.name:

# this only works if all children of the list have the same parent, throw
# an error if we can detect that that is not the case

if len( plist) > 1 and plist[0].parent != plist[1].parent:
if len(plist) > 1 and plist[0].parent != plist[1].parent:
raise Exception( "Error during translation!" )

# generate the updated name, and also make a copy of the PortList to make
# sure we aren't impacting any other AST references to this object

name = '{}${}'.format( plist[0].parent.name, plist.name )
name = '{}${}'.format( plist.parent.name, plist.name )
node._object = PortList( node._object )
node._object.name = name

Expand Down Expand Up @@ -840,6 +840,10 @@ def visit_Subscript( self, node ):
# visit value to find nested subscripts
self.visit( node.value )

if (isinstance( node._object, list ) and
isinstance( node._object[0], list )):
self.arrays.remove( node._object[0] )

# visit slice to find params
# _is_lhs is false because vars in index are only read, not written!
stash_is_lhs, self._is_lhs = self._is_lhs, False
Expand Down

0 comments on commit 45c8a1d

Please sign in to comment.