Python has powerful built-in data types that can be useful to model hardware memories. This can be merely a matter of putting an interface around some data type operations.
For example, a dictionary comes in handy to model sparse memory structures. (In other languages, this data type is called associative array, or hash table.) A sparse memory is one in which only a small part of the addresses is used in a particular application or simulation. Instead of statically allocating the full address space, which can be large, it is better to dynamically allocate the needed storage space. This is exactly what a dictionary provides. The following is an example of a sparse memory model:
def sparseMemory(dout, din, addr, we, en, clk):
""" Sparse memory model based on a dictionary.
Ports:
dout -- data out
din -- data in
addr -- address bus
we -- write enable: write if 1, read otherwise
en -- interface enable: enabled if 1
clk -- clock input
"""
memory = {}
@always(clk.posedge)
def access():
if en:
if we:
memory[addr.val] = din.val
else:
dout.next = memory[addr.val]
return access
Note how we use the val attribute of the din signal, as
we don't want to store the signal object itself, but its current
value. Similarly, we use the val attribute of the addr
signal as the dictionary key.
In many cases, MyHDL code uses a signal's current value
automatically when there is no ambiguity: for example, when a signal
is used in an expression. However, in other cases such as in this
example you have to refer to the value explicitly: for example, when
the Signal is used as an index, or when it is not used in an
expression. One option is to use the val attribute, as in this
example. Another possibility is to use the int() or
bool() functions to typecast the Signal to an integer or a
boolean value. These functions are also useful with intbv
objects.
As a second example, we will demonstrate how to use a list to model a synchronous fifo:
def fifo(dout, din, re, we, empty, full, clk, maxFilling=sys.maxint):
""" Synchronous fifo model based on a list.
Ports:
dout -- data out
din -- data in
re -- read enable
we -- write enable
empty -- empty indication flag
full -- full indication flag
clk -- clock input
Optional parameter:
maxFilling -- maximum fifo filling, "infinite" by default
"""
memory = []
@always(clk.posedge)
def access():
if we:
memory.insert(0, din.val)
if re:
dout.next = memory.pop()
filling = len(memory)
empty.next = (filling == 0)
full.next = (filling == maxFilling)
return access
Again, the model is merely a MyHDL interface around some operations on a list: insert() to insert entries, pop() to retrieve them, and len() to get the size of a Python object.
About this document