Token Bucket Rate Limiter
Medium · Sequential · SystemVerilog
Design a parameterized token bucket rate limiter that tracks a saturating token counter and grants multi-token burst requests only up to the tokens available.
The bucket holds at most {BUCKET_DEPTH} tokens. On reset, the bucket starts full: {level} $=$ {BUCKET_DEPTH}.
**Refill.** When {refill_tick} is asserted, {REFILL_RATE} tokens are added to the bucket, saturating at {BUCKET_DEPTH}. That is, the level after a refill is $\min(\text{level} + \text{REFILL\_RATE},\ \text{BUCKET\_DEPTH})$.
**Consume.** {granted} equals $\min(\text{req\_count},\ \text{level\_after\_refill})$ — the actual number of tokens consumed this cycle. {level} decrements by {granted}. When {req_count}$=0$, no tokens are consumed and {granted}$=0$. When {req_count} exceeds level_after_refill, only level_after_refill tokens are consumed: {granted}$=\text{level\_after\_refill}$ and {level} drops to $0$.
**Simultaneous refill and consume.** When both {refill_tick} and {req_count}$>0$ are asserted in the same cycle, the refill is applied first (with saturation), and then the consume is evaluated against the post-refill level. For example: {req_count}$=5$, {level}$=3$, {refill_tick}$=1$, {REFILL_RATE}$=1$ — post-refill level$=4$, so {granted}$=4$ and {level}$=0$.
**Timing.** {granted} and {level} are registered outputs: they reflect the result of the operation that occurred on the previous rising edge of {clk}. On each rising edge of {clk}: