3.3.2 Modeling memories with built-in types

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