In [1]:
import magma as m
m.set_mantle_target("ice40")
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)
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
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.
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