Counter


In [1]:
import magma as m
m.set_mantle_target("ice40")

Counter Circuit

To implement a counter we can use the Register primitive and the + operator.


In [2]:
from mantle import Register

class SimpleCounter4(m.Circuit):
    IO = ["O", m.Out(m.UInt[4])] + m.ClockInterface()
    @classmethod
    def definition(io):
        reg4 = Register(4, _type=m.UInt)
        io.O <= reg4(reg4.O + 1)


import lattice ice40
import lattice mantle40
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-8f0e9d6e0dbd> in <module>
      1 from mantle import Register
      2 
----> 3 class SimpleCounter4(m.Circuit):
      4     IO = ["O", m.Out(m.UInt[4])] + m.ClockInterface()
      5     @classmethod

~/git/magma/magma/circuit.py in __new__(metacls, name, bases, dct)
    476             if hasattr(self, 'definition'):
    477                  pushDefinition(self)
--> 478                  self.definition()
    479                  self.check_unconnected()
    480                  self._is_definition = True

<ipython-input-2-8f0e9d6e0dbd> in definition(io)
      6     def definition(io):
      7         reg4 = Register(4, _type=m.UInt)
----> 8         io.O <= reg4(reg4.O + 1)

~/git/mantle/mantle/common/operator.py in wrapper(*args, **kwargs)
     72     @wraps(fn)
     73     def wrapper(*args, **kwargs):
---> 74         retval = fn(*args, **kwargs)
     75         T = type(args[0])
     76         if isinstance(T, m.UIntKind):

~/git/mantle/mantle/common/operator.py in wrapped(*args, **kwargs)
     47             raise TypeError(
     48                 "Currently Arguments to operators must be of the same type")
---> 49         return fn(width, *args, **kwargs)
     50     return wrapped
     51 

~/git/mantle/mantle/common/operator.py in _wrapped_inner(*args, **kwargs)
     58         @wraps(fn)
     59         def _wrapped_inner(*args, **kwargs):
---> 60             return fn(*closure_args, *args, **kwargs)
     61         return _wrapped_inner
     62     return _wrapped

~/git/mantle/mantle/common/operator.py in operator(circuit, name, width, *args, **kwargs)
    129                 if len(args) > 2:
    130                     raise Exception(f"{name} operator expects 2 arguments")
--> 131                 return circuit(width, T=type(args[0]), **kwargs)(*args)
    132             else:
    133                 return circuit(len(args), width, **kwargs)(*args)

~/git/mantle/mantle/common/arith.py in Add(n, cin, cout, T, **kwargs)
      6 
      7 def Add(n, cin=False, cout=False, T=m.Bits, **kwargs):
----> 8     return DefineAdd(n, cin=cin, cout=cout, T=T)(**kwargs)
      9 
     10 

TypeError: DefineAdd() got an unexpected keyword argument 'T'

The above example shows how to create a circuit by subclassing Circuit. Another way to construct a circuit is using a function that builds the circuit.


In [ ]:
def SimpleCounter4():
    _SimpleCounter4 = DefineCircuit('SimpleCounter4', "O", m.Out(m.UInt[4]), *m.ClockInterface())
    reg4 = Register(4)
    _SimpleCounter4.O <= reg4(reg4.O + 1)
    EndCircuit()
    return _SimpleCounter4

Counter Circuit Generator

The above example creates a counter of fixed size 4. How can we make a more general counter of arbitray width?


In [ ]:
def DefineCounter(n):
    class _Counter(m.Circuit):
        name = f'Counter{n}'
        IO = ["O", m.Out(m.UInt[n])] + m.ClockInterface()
        @classmethod
        def definition(io):
            reg = Register(n, type=m.UInt)
            io.O <= reg(reg.O) + 1)
    return _Counter

def Counter(n):
    return DefineCounter(n)()

The definition of the generated n-bit counter can use the n parameter that is captured in the closure environment.

Test bench


In [ ]:
from loam.boards.icestick import IceStick

N = 30

icestick = IceStick()
icestick.Clock.on()
for i in range(8):
    icestick.J3[i].output().on()
    
main = icestick.DefineMain()

counter = Counter(N)
main.J3 <= counter()[N-8:N]

m.EndDefine()

We can compile and inspect the verilog.


In [ ]:
m.compile("build/counter", main)

In [ ]:
%%bash
cd build
yosys -q -p 'synth_ice40 -top main -blif counter.blif' counter.v
arachne-pnr -q -d 1k -o counter.txt -p counter.pcf counter.blif 
icepack counter.txt counter.bin
#iceprog counter.bin

In [ ]:
%cat build/counter.v