Trying to create a fifo through a queue

I am trying to create a fifo by a queue (this is also mentioned in the MyHDL manual) but get errors when I try to convert it to VHDL. Not sure if this are MyHDL errors or normal Python errors.

convert_model.py

from myhdl import Signal,intbv, ResetSignal
from fifo_queue import Fifo
from rw_fifo import *

def convert_rw_fifo(hdl):
#assign default/initial values to signals

ip_rst = ResetSignal(0, active=1, isasync=True)
ip_clk = Signal(bool(0))
ResetError = Signal(bool(0))
write = Signal(bool(0))
write_data = Signal(intbv(val=0, min=0, max=2**16))
read = Signal(bool(0))

rw_fifo_1 = rw_fifo(ip_rst, ip_clk, ResetError, write, write_data, read)
rw_fifo_1.convert(hdl=hdl)

#------------------------------------------------------------------------------

Main

#------------------------------------------------------------------------------
if name == ‘main’ :
convert_rw_fifo(hdl=‘VHDL’)

fifo_queue.py

#from myhdl import (Signal, ResetSignal, intbv, modbv, always, always_comb, always_seq)
import queue

“”"
FIFO definition with queue
“”"

class Fifo():

def init (self, depth, width, almost_full_level, almost_empty_level):
“”" create queue and attributes “”"
self.fifo = queue.Queue(depth)
self.depth = depth
self.width = width
self.full_flag = 0
self.empty_flag = 1
self.almost_full_level = almost_full_level
self.almost_empty_level = almost_empty_level
“”" keep track of number of values in fifo “”"
self.level = 0

def put(self, symbol):
“”" store a value in fifo if not full “”"
if self.level != self.depth:
self.fifo.put(symbol, block=False, timeout=None)
self.level = self.level + 1

def get(self):
“”" get a value from fifo if not empty “”"
if self.level != 0:
symbol = self.fifo.get(block=False)
self.level = self.level - 1
return symbol

def is_full(self):
“”" check if fifo is full “”"
return self.limit_reached(self.depth)

def is_empty(self):
“”" check if fifo is full “”"
return self.limit_reached(0)

def is_almost_full(self):
“”" check if fifo is almost full “”"
return self.limit_reached(self.almost_full_level)

def is_almost_empty(self):
“”" check if fifo is almost empty “”"
return self.limit_reached(self.almost_empty_level)

def limit_reached(self, limit):
if self.level == limit:
return True
else:
return False

def reset(self):
“”" reset level counter “”"
self.fifo = queue.Queue(self.depth)
self.level = 0

#------------------------------------------------------------------------------

Test functions

#------------------------------------------------------------------------------
def tst_queue_1():
depth = 10
width = 3
almost_full_level = 9
almost_empty_level = 1

Print all methods

print(dir(Fifo))

Testing Put element:

header_fifo = Fifo(depth, width, almost_full_level, almost_empty_level)

fifo = Fifo(depth, width, almost_full_level, almost_empty_level)

for i in range(11):
print(‘Putting {:d}\n’.format(i))
if header_fifo.is_full():

if fifo.is_full():

  print('\t\tShit, the fifo is full')
else:
  header_fifo.put(i)

a=1

Testing Get element:

for i in range(11):
if header_fifo.is_empty():
print(’\t\tShit, the fifo is empty’)
else:
symbol = header_fifo.get()
print(‘Getting {:d}\n’.format(symbol))

header_fifo.put(20)
header_fifo.put(30)
header_fifo.reset()
if header_fifo.is_empty():
print(‘The fifo is empty and should be\n’)
#------------------------------------------------------------------------------

Main

#------------------------------------------------------------------------------
if name == ‘main’ :
tst_queue_1()

rw_fifo.py

from myhdl import block, instance, Signal, ResetSignal, intbv, modbv, concat, always, always_comb, always_seq
from fifo_queue import Fifo

@block
def rw_fifo (ip_rst, ip_clk, ResetError, write, write_data, read):

“”" create fifo
“”"
header_fifo = Fifo(32, 16, 16-4, 4)
write_data = Signal(intbv(val=0, min=0, max=216))
read_data = Signal(intbv(val=0, min=0, max=2
16))

@always_seq (ip_clk.negedge, reset=ip_rst)
def fifo_write():

""" 
  clear fifo's at reset
"""
if ResetError == 1: 
  header_fifo.reset()
else: 
  """ write to fifo """
  if write == 1 and header_fifo.is_full==0:
    header_fifo.put(write_data)

@always_comb
def fifo_read():

""" read from fifo if requested and there is data """
if read == 1 and header_fifo.is_empty() == 0:
  """ change format only """
  read_data = header_fifo.get()

return fifo_write, fifo_read

The error is that it cannot find the reset method in the class definition. If I run the testfunction in the fifo_queue it seems to work.

Albert,

can you post your code like this:

```python
your code goes here between the backticks
```

file convert_model.py
‘’’
from myhdl import Signal,intbv, ResetSignal
from fifo_queue import Fifo
from rw_fifo import *

def convert_rw_fifo(hdl):
#assign default/initial values to signals

ip_rst = ResetSignal(0, active=1, isasync=True)
ip_clk = Signal(bool(0))
ResetError = Signal(bool(0))
write = Signal(bool(0))
write_data = Signal(intbv(val=0, min=0, max=2**16))
read = Signal(bool(0))

rw_fifo_1 = rw_fifo(ip_rst, ip_clk, ResetError, write, write_data, read)
rw_fifo_1.convert(hdl=hdl)

#------------------------------------------------------------------------------

Main

#------------------------------------------------------------------------------
if name == ‘main’ :
convert_rw_fifo(hdl=‘VHDL’)
‘’’

file: fifo_queue.py
‘’’
#from myhdl import (Signal, ResetSignal, intbv, modbv, always, always_comb, always_seq)
import queue

“”"
FIFO definition with queue
“”"

class Fifo():

def init (self, depth, width, almost_full_level, almost_empty_level):
“”" create queue and attributes “”"
self.fifo = queue.Queue(depth)
self.depth = depth
self.width = width
self.full_flag = 0
self.empty_flag = 1
self.almost_full_level = almost_full_level
self.almost_empty_level = almost_empty_level
“”" keep track of number of values in fifo “”"
self.level = 0

def put(self, symbol):
“”" store a value in fifo if not full “”"
if self.level != self.depth:
self.fifo.put(symbol, block=False, timeout=None)
self.level = self.level + 1

def get(self):
“”" get a value from fifo if not empty “”"
if self.level != 0:
symbol = self.fifo.get(block=False)
self.level = self.level - 1
return symbol

def is_full(self):
“”" check if fifo is full “”"
return self.limit_reached(self.depth)

def is_empty(self):
“”" check if fifo is full “”"
return self.limit_reached(0)

def is_almost_full(self):
“”" check if fifo is almost full “”"
return self.limit_reached(self.almost_full_level)

def is_almost_empty(self):
“”" check if fifo is almost empty “”"
return self.limit_reached(self.almost_empty_level)

def limit_reached(self, limit):
if self.level == limit:
return True
else:
return False

def reset(self):
“”" reset level counter “”"
self.fifo = queue.Queue(self.depth)
self.level = 0

‘’’

file: rw_fifo.py
‘’’
from myhdl import block, instance, Signal, ResetSignal, intbv, modbv, concat, always, always_comb, always_seq
from fifo_queue import Fifo

@block
def rw_fifo (ip_rst, ip_clk, ResetError, write, write_data, read):

“”" create fifo
“”"
header_fifo = Fifo(32, 16, 16-4, 4)
write_data = Signal(intbv(val=0, min=0, max=216))
read_data = Signal(intbv(val=0, min=0, max=2
16))

@always_seq (ip_clk.negedge, reset=ip_rst)
def fifo_write():

""" 
  clear fifo's at reset
"""
if ResetError == 1: 
  header_fifo.reset()
else: 
  """ write to fifo """
  if write == 1 and header_fifo.is_full==0:
    header_fifo.put(write_data)

@always_comb
def fifo_read():

""" read from fifo if requested and there is data """
if read == 1 and header_fifo.is_empty() == 0:
  """ change format only """
  read_data = header_fifo.get()

return fifo_write, fifo_read

------------------------------------------------------------------------------

Test functions

------------------------------------------------------------------------------

def tst_queue_1():
depth = 10
width = 3
almost_full_level = 9
almost_empty_level = 1

Print all methods

#print(dir(Fifo))

Testing Put element:

header_fifo = Fifo(depth, width, almost_full_level, almost_empty_level)

fifo = Fifo(depth, width, almost_full_level, almost_empty_level)

for i in range(11):
print(‘Putting {:d}\n’.format(i))
if header_fifo.is_full():
# if fifo.is_full():
print(’\t\tShit, the fifo is full’)
else:
header_fifo.put(i)
a = 1

Testing Get element:

for i in range(11):
if header_fifo.is_empty():
print(’\t\tShit, the fifo is empty’)
else:
symbol = header_fifo.get()
print(‘Getting {:d}\n’.format(symbol))

header_fifo.put(20)
header_fifo.put(30)
header_fifo.reset()
if header_fifo.is_empty():
print(‘The fifo is empty and should be\n’)

------------------------------------------------------------------------------

Main

------------------------------------------------------------------------------

if name == ‘main’:
tst_queue_1()

‘’’

That didn’t work; the three backticks look like this: ```
image

I copied the source as is and tried to edit it, but the indentation has gone lost and I refrained from guessing your intentions in the code :slight_smile:

Or click on the indicated icon:

Josyb, sorry for using the wrong ticks. Find a retry below.

The fifo_queue.py file

#from myhdl import (Signal, ResetSignal, intbv, modbv, always, always_comb, always_seq)
import queue

"""
  FIFO definition with queue
"""


class Fifo():

  def __init__ (self, depth, width, almost_full_level, almost_empty_level):
    """ create queue and attributes """
    self.fifo       = queue.Queue(depth)
    self.depth      = depth
    self.width      = width
    self.full_flag  = 0
    self.empty_flag = 1
    self.almost_full_level  = almost_full_level
    self.almost_empty_level = almost_empty_level
    """ keep track of number of values in fifo """
    self.level = 0
    
  def put(self, symbol):
    """ store a value in fifo if not full """
    if self.level != self.depth:
      self.fifo.put(symbol, block=False, timeout=None)
      self.level = self.level + 1   

  def get(self):
    """ get a value from fifo if not empty """
    if self.level != 0:
      symbol = self.fifo.get(block=False)
      self.level = self.level - 1
      return symbol

  def is_full(self):
    """ check if fifo is full """
    return self.limit_reached(self.depth)

  def is_empty(self):
    """ check if fifo is full """
    return self.limit_reached(0)

  def is_almost_full(self):
    """ check if fifo is almost full """
    return self.limit_reached(self.almost_full_level)

  def is_almost_empty(self):
    """ check if fifo is almost empty """
    return self.limit_reached(self.almost_empty_level)

  def limit_reached(self, limit):
    if self.level == limit:
      return True
    else:
      return False
  
  def reset(self):
    """ reset level counter """
    self.fifo  = queue.Queue(self.depth)
    self.level = 0

The rw_fifo.py file

from myhdl import block, instance, Signal, ResetSignal, intbv, modbv, concat, always, always_comb, always_seq
from fifo_queue import Fifo

@block
def rw_fifo (ip_rst, ip_clk, ResetError, write, write_data, read):

  """ create fifo
  """
  header_fifo  = Fifo(32, 16, 16-4, 4)
  write_data   = Signal(intbv(val=0, min=0, max=2**16))
  read_data    = Signal(intbv(val=0, min=0, max=2**16))
    
  @always_seq (ip_clk.negedge, reset=ip_rst)
  def fifo_write():

    """ 
      clear fifo's at reset
    """
    if ResetError == 1: 
      header_fifo.reset()
    else: 
      """ write to fifo """
      if write == 1 and header_fifo.is_full==0:
        header_fifo.put(write_data)

  @always_comb 
  def fifo_read():

    """ read from fifo if requested and there is data """
    if read == 1 and header_fifo.is_empty() == 0:
      """ change format only """
      read_data = header_fifo.get()

  return fifo_write, fifo_read


# ------------------------------------------------------------------------------
# Test functions
# ------------------------------------------------------------------------------
def tst_queue_1():
  depth = 10
  width = 3
  almost_full_level = 9
  almost_empty_level = 1

  # Print all methods

  #print(dir(Fifo))

  # Testing Put element:
  header_fifo = Fifo(depth, width, almost_full_level, almost_empty_level)

  #  fifo = Fifo(depth, width, almost_full_level, almost_empty_level)
  for i in range(11):
    print('Putting {:d}\n'.format(i))
    if header_fifo.is_full():
      #    if fifo.is_full():
      print('\t\tShit, the fifo is full')
    else:
      header_fifo.put(i)
  a = 1

  # Testing Get element:
  for i in range(11):
    if header_fifo.is_empty():
      print('\t\tShit, the fifo is empty')
    else:
      symbol = header_fifo.get()
      print('Getting {:d}\n'.format(symbol))

  header_fifo.put(20)
  header_fifo.put(30)
  header_fifo.reset()
  if header_fifo.is_empty():
    print('The fifo is empty and should be\n')


# ------------------------------------------------------------------------------
# Main
# ------------------------------------------------------------------------------
if __name__ == '__main__':
  tst_queue_1()
     

The convert_model.py file

from myhdl import Signal,intbv, ResetSignal
from fifo_queue import Fifo
from rw_fifo import *

def convert_rw_fifo(hdl):
#assign default/initial values to signals

  ip_rst                = ResetSignal(0, active=1, isasync=True) 
  ip_clk                = Signal(bool(0))    
  ResetError            = Signal(bool(0))  
  write                 = Signal(bool(0))
  write_data            = Signal(intbv(val=0, min=0, max=2**16))
  read                  = Signal(bool(0))

  rw_fifo_1 = rw_fifo(ip_rst, ip_clk, ResetError, write, write_data, read)
  rw_fifo_1.convert(hdl=hdl)

#------------------------------------------------------------------------------
# Main
#------------------------------------------------------------------------------
if __name__ == '__main__' :
  convert_rw_fifo(hdl='VHDL')

Thanks already for the effort you did.

Best Regards,

Albert Hoevenaars

Hi Albert,

That went better.
I can run your tst_queue_1() and it seems to do the expected. But that is standard Python code.
Now MyHDL is a bit stubborn and conversion is very picky.
First problem is that it doesn’t do method calls like header_fifo.reset(). The next issue will be that it won’t know what to do with the queue.Queue object; it doesn’t contain any valid MyHDL code.
I checked the queue example in the MyHDL Manual. This will actually simulate, but it will not convert. (It also needs some work to bring it up to 0.11 standard)
What is your goal?

Best regards,
Josy

Josyb,

thanks for looking into my code. My goal was to create a fifo and I was looking how to do that. A list could be used but I also read about queue’s, which is just what a fifo does. So I used that. Also the queue example in the MyHDL guide set me on that track. And a queue used in a class looked very nice and rather simple. I found some other fifo examples but they used memory and read/write pointers (which is just what a fifo uses, I know).
I have to create testbenches for a very big design and I am now working bottom up. First creating small testbenches, but those are already difficult enough because of the use of Xilinx IP. Fifo and memories are used very often. For now I decided to create a design in HDL Designer were I convert the code from the DUT to MyHDL code (written in a complete other way) and use the Xilinx IP blocks that were already in the design. This gives me a complete model of the DUT. Then I use some blocks from UVVM to complete the testbench.
Conclusion is now that I do not have to make models for IP blocks. I simply reused because they are already in our libraries of HDL Designer. Makes live much simpler.

When I use a fifo some flags are also stored in the fifo along with the signed data. They need to be split-off at the output of the fifo. But splitting of the signed data value from the flags give me always positive numbers. Some conversion is needed. Still need to figure out how to do that. But learning every day more and more.

So thanks again for having a look in my problems.

Best Regards,

Albert Hoevenaars