pymtl / pymtl3

Pymtl 3 (Mamba), an open-source Python-based hardware generation, simulation, and verification framework
BSD 3-Clause "New" or "Revised" License
388 stars 46 forks source link

Example fails: type object 'NamedObject' has no attribute '_elaborate_stack' #218

Closed yurivict closed 2 years ago

yurivict commented 2 years ago

I'm trying the example from this lecture. Code from Figure 8 and Figure 9 there.

The code fails:

$ ./sim.py 
Traceback (most recent call last):
  File "./sim.py", line 8, in <module>
    from RegIncr import RegIncr
  File "/disk-samsung/freebsd-ports/cad/py-pymtl/RegIncr.py", line 35, in <module>
    def block2():
  File "/usr/local/lib/python3.8/site-packages/pymtl3/dsl/ComponentLevel1.py", line 28, in update
    NamedObject._elaborate_stack[-1]._update( blk )
AttributeError: type object 'NamedObject' has no attribute '_elaborate_stack'

example.zip

cbatten commented 2 years ago

Thanks for your interest in using PyMTL3! I took a look at your example code. This is what your registered incrementer looks like:

#=========================================================================
# RegIncr
#=========================================================================
# This is a simple model for a registered incrementer. An eight-bit value
# is read from the input port, registered, incremented by one, and
# finally written to the output port.

from pymtl3 import *

class RegIncr( Component ):

  # Constructor

  def construct( s ):

    # Port-based interface

    s.in_ = InPort ( Bits8 )
    s.out = OutPort ( Bits8 )

    # update_ff block modeling register

    s.reg_out = Wire( 8 ) # 8 is the same as Bits8 for Wire/InPort/OutPort

    @update_ff
    def block1():
      if s.reset:
        s.reg_out <<= 0
      else:
        s.reg_out <<= s.in_

# update block modeling incrementer

@update
def block2():
  s.out @= s.reg_out + 1

Notice how block2 is not indented correctly ... this is confusing the PyMTL3 framework since block2 is using an update decorator but is not in a construct method ... if you indent block2 as in Figure 8 it works:

#=========================================================================
# RegIncr
#=========================================================================
# This is a simple model for a registered incrementer. An eight-bit value
# is read from the input port, registered, incremented by one, and
# finally written to the output port.

from pymtl3 import *

class RegIncr( Component ):

  # Constructor

  def construct( s ):

    # Port-based interface

    s.in_ = InPort ( Bits8 )
    s.out = OutPort ( Bits8 )

    # update_ff block modeling register

    s.reg_out = Wire( 8 ) # 8 is the same as Bits8 for Wire/InPort/OutPort

    @update_ff
    def block1():
      if s.reset:
        s.reg_out <<= 0
      else:
        s.reg_out <<= s.in_

    # update block modeling incrementer

    @update
    def block2():
      s.out @= s.reg_out + 1