Marko Kozomora
Marko Kozomora

Reputation: 85

PyGears How to make counter

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

Answers (1)

Bogdan Vukobratovic
Bogdan Vukobratovic

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:

  1. 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  
    
  2. 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

Related Questions