Reputation: 85
I want to make a counter which can start counting at posedge of a specific signal (enable signal). And once it counts to 256, stop counting, set the counter to 0 and output something.
Upvotes: 2
Views: 78
Reputation: 161
When designing with PyGears, you should try to think more in terms of functions (although asynchronous) that are being invoked by receiving commands via input interfaces. Instead of thinking of the enable
signal that triggers the counter, try to think of a counter you described as a function that receives a number to count to as an input command and outputs something once it's done counting. There are two ways we could go about implementing this:
An async gear, in which we write procedural code to describe the logic
from pygears import gear, sim
from pygears.typing import Uint
from pygears.sim import log
from pygears.lib import once, qrange
@gear
async def counter(cmd: Uint, *, something) -> b'type(something)':
async with cmd as c:
async for i in qrange(c):
pass
yield something
@gear
async def collect(data):
async with data as d:
log.info(f'Got something: {d}')
once(val=256) \
| counter(something=Uint[8](2)) \
| collect
sim()
Here, the counter
has an interface called cmd
, where a number of cycles to count is received, and a compile time parameter called something
, which will be sent through the output interface once the counting is done. In the body of the function, we first wait for the input command to arrive: async with cmd as c:
, next we wait for the counter to finish and finally we output something
. qrange
is a builtin gear and you are welcome to inspect its implementation here: rng.py
Then there's the collect
gear which simply prints out whatever it receives. Finally, we generate the command for the counter
using once
, and feed the output of the counter
to the collect
module. When sim()
is invoked, we get the following output showing that collect
got something
in the cycle 255:
0 [INFO]: -------------- Simulation start --------------
255 /collect [INFO]: Got something: u8(2)
256 [INFO]: ----------- Simulation done ---------------
256 [INFO]: Elapsed: 0.03
We could use a hierarchical gear to connect existing builtin modules to achieve the same thing:
from pygears import gear, sim
from pygears.typing import Uint
from pygears.sim import log
from pygears.lib import once, qrange, when
@gear
def counter(cmd: Uint, *, something):
last = qrange(cmd)['eot']
return when(last, something)
@gear
async def collect(data):
async with data as d:
log.info(f'Got something: {d}')
once(val=256) \
| counter(something=Uint[8](2)) \
| collect
sim()
Everything is pretty much the same, except that the counter
isn't defined with the async
keyword, meaning that it is a hierarchical gear and only describes interconnection between its submodules. The qrange
gear outputs both the iterator and a flag, called eot
(for end-of-transaction), which marks the last count. We feed eot
(via eot
variable) to the when
gear that will only output something
when it sees value True
on eot
interface.
Upvotes: 1