{{ message }}

How do you make a bounded up-down counter without modulo?#492

Closed
opened this issue Aug 27, 2020 · 4 comments
Closed

How do you make a bounded up-down counter without modulo?#492

opened this issue Aug 27, 2020 · 4 comments
Labels BrettRD commented Aug 27, 2020

 Modulo operators for negative numbers are a known issue, and the operator is not implemented on stable. What is the work around for a decrement to underflow around an arbitrary bounds? This test shows the modulo producing strange results on decrement that disappear if you force the range into positive. from nmigen import * from nmigen.back.pysim import Simulator class counter_thing(Elaboratable): def __init__(self, max_count, rst): self.dir = Signal(1) self.mod_pos = Signal(range(max_count), reset=rst) self.mod_neg = Signal(range(max_count), reset=rst) def elaborate(self, platform): m = Module() m.d.sync += self.mod_pos.eq((self.mod_pos + max_count - 1) % max_count) m.d.sync += self.mod_neg.eq((self.mod_neg - 1) % max_count) return m def test(): count = rst for _ in range(2*max_count): yield count = (count - 1) % max_count print(str((yield dut.mod_pos)) + ', ' + str((yield dut.mod_neg)) + ', ' + str(count)) assert (yield dut.mod_pos) == count # passes assert (yield dut.mod_pos) == (yield dut.mod_neg) # fails after underflow if __name__ == "__main__": max_count = 17 rst = 13 dut = counter_thing(max_count, rst) sim = Simulator(dut) sim.add_clock(1) sim.add_sync_process(test) # or sim.add_sync_process(process), see below sim.run() The text was updated successfully, but these errors were encountered: whitequark commented Aug 29, 2020 • edited

 What is the work around for a decrement to underflow around an arbitrary bounds? Assuming you are interested in a counter that increments or decrements by 1 each cycle, something like this would give you arbitrary overflow bounds: class BoundedCounter(Elaboratable): def __init__(self, min, max): self.min = min self.max = max self.up = Signal(1) self.count = Signal(range(min, max + 1)) def elaborate(self, platform): m = Module() with m.If(self.up): with m.If(self.count == max): m.d.sync += self.count.eq(min) with m.Else(): m.d.sync += self.count.eq(self.count + 1) with m.Else(): with m.If(self.count == min): m.d.sync += self.count.eq(max) with m.Else(): m.d.sync += self.count.eq(self.count - 1) return m DaKnig commented Sep 4, 2020

 I'd suggest to avoid the % and / operators in hardware design (when you divide by a number that is not a power of 2). division is slow and expensive in hardware, it would take more than one clock at a rate users usually want to work, that is why usually backends don't implement that in synthesizable code regardless of what language you would use.