In the previous section, we used Python data types for modeling. If such a type is used inappropriately, Python's run time error system will come into play. For example, if we access an address in the sparseMemory model that was not initialized before, we will get a traceback similar to the following (some lines omitted for clarity):
Traceback (most recent call last):
...
File "sparseMemory.py", line 31, in access
dout.next = memory[addr.val]
KeyError: Signal(51)
Similarly, if the fifo is empty, and we attempt to read from
it, we get:
Traceback (most recent call last):
...
File "fifo.py", line 34, in fifo
dout.next = memory.pop()
IndexError: pop from empty list
Instead of these low level errors, it may be preferable to define
errors at the functional level. In Python, this is typically done by
defining a custom Error exception, by subclassing the standard
Exception class. This exception is then raised explicitly when
an error condition occurs.
For example, we can change the sparseMemory function as follows (with the doc string is omitted for brevity):
class Error(Exception):
pass
def sparseMemory2(dout, din, addr, we, en, clk):
memory = {}
@always(clk.posedge)
def access():
if en:
if we:
memory[addr.val] = din.val
else:
try:
dout.next = memory[addr.val]
except KeyError:
raise Error, "Uninitialized address %s" % hex(addr)
return access
This works by catching the low level data type exception, and raising the custom exception with an appropriate error message instead. If the sparseMemory function is defined in a module with the same name, an access error is now reported as follows:
Traceback (most recent call last):
...
File "sparseMemory.py", line 61, in access
raise Error, "Uninitialized address %s" % hex(addr)
Error: Uninitialized address 0x33
Likewise, the fifo function can be adapted as follows, to report underflow and overflow errors:
class Error(Exception):
pass
def fifo2(dout, din, re, we, empty, full, clk, maxFilling=sys.maxint):
memory = []
@always(clk.posedge)
def access():
if we:
memory.insert(0, din.val)
if re:
try:
dout.next = memory.pop()
except IndexError:
raise Error, "Underflow -- Read from empty fifo"
filling = len(memory)
empty.next = (filling == 0)
full.next = (filling == maxFilling)
if filling > maxFilling:
raise Error, "Overflow -- Max filling %s exceeded" % maxFilling
return access
In this case, the underflow error is detected as before, by catching a low level exception on the list data type. On the other hand, the overflow error is detected by a regular check on the length of the list.
About this document