gs4 = m_sync_mbits(rclk, rrst, wptr, rq2_wptr) @always_comb def rtl_assigns(): fbus.empty.next = rempty fbus.full.next = wfull _we = Signal(bool(0)) @always_comb def rtl_wr(): _we.next = fbus.wr and not fbus.full #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Memory for the FIFO g_fifomem = m_fifo_mem_generic(wclk, _we, fbus.wdata, waddr, rclk, fbus.rdata, raddr, mem_size=fbus.size) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # --Text from the paper-- # The read pointer is a dual nbit Gray code counter. The nbit # pointer (rptr) is passed to the write clock domain through the # syncs. The (n-1)bit pointer (raddr) is used to address the FIFO # buffer. The FIFO empty output is registered and is asserted on # the next rising rclk edge when the next rptr value equals the # sync wptr value. rbin = Signal(modbv(0)[Asz+1:]) #raddr.assign(rbin[Asz:0] @always_seq(rclk.posedge, reset=rrst)
def m_fifo_sync(clock, reset, fbus): """ Simple synchronous FIFO PORTS ===== PARAMETERS ========== """ # @todo: this is intended to be used for small fast fifo's but it # can be used for large synchronous fifo as well N = fbus.size if fmod(log(N, 2), 1) != 0: Asz = int(ceil(log(N, 2))) N = 2**Asz print("@W: m_fifo_sync only supports power of 2 size") print(" forcing size (depth) to %d instread of " % (N, fbus.size)) wptr = Signal(modbv(0, min=0, max=N)) rptr = Signal(modbv(0, min=0, max=N)) _vld = Signal(False) # generic memory model g_fifomem = m_fifo_mem_generic(clock, fbus.wr, fbus.wdata, wptr, clock, fbus.rdata, rptr, mem_size=fbus.size) # @todo: almost full and almost empty flags read = fbus.rd write = fbus.wr @always_seq(clock.posedge, reset=reset) def rtl_fifo(): if fbus.clear: wptr.next = 0 rptr.next = 0 fbus.full.next = False fbus.empty.next = True elif read and not write: fbus.full.next = False if not fbus.empty: rptr.next = rptr + 1 if rptr == (wptr - 1): fbus.empty.next = True elif write and not read: fbus.empty.next = False if not fbus.full: wptr.next = wptr + 1 if wptr == (rptr - 1): fbus.full.next = True elif write and read: wptr.next = wptr + 1 rptr.next = rptr + 1 _vld.next = read @always_comb def rtl_assign(): fbus.rvld.next = _vld & fbus.rd nvacant = Signal(intbv(N, min=-0, max=N + 1)) # # empty slots ntenant = Signal(intbv(0, min=-0, max=N + 1)) # # filled slots @always_seq(clock.posedge, reset=reset) def dbg_occupancy(): if fbus.clear: nvacant.next = N ntenant.next = 0 else: v = nvacant f = ntenant if fbus.rvld: v = v + 1 f = f - 1 if fbus.wr: v = v - 1 f = f + 1 nvacant.next = v ntenant.next = f fbus.count = ntenant return ( g_fifomem, rtl_fifo, rtl_assign, dbg_occupancy, )
def rtl_assigns(): fbus.empty.next = rempty fbus.full.next = wfull _we = Signal(bool(0)) @always_comb def rtl_wr(): _we.next = fbus.wr and not fbus.full #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Memory for the FIFO g_fifomem = m_fifo_mem_generic(wclk, _we, fbus.wdata, waddr, rclk, fbus.rdata, raddr, mem_size=fbus.size) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # --Text from the paper-- # The read pointer is a dual nbit Gray code counter. The nbit # pointer (rptr) is passed to the write clock domain through the # syncs. The (n-1)bit pointer (raddr) is used to address the FIFO # buffer. The FIFO empty output is registered and is asserted on # the next rising rclk edge when the next rptr value equals the # sync wptr value. rbin = Signal(modbv(0)[Asz + 1:]) #raddr.assign(rbin[Asz:0]
def m_fifo_sync(clock, reset, fbus): """ Simple synchronous FIFO PORTS ===== PARAMETERS ========== """ # @todo: this is intended to be used for small fast fifo's but it # can be used for large synchronous fifo as well N = fbus.size if fmod(log(N, 2), 1) != 0: Asz = int(ceil(log(N, 2))) N = 2 ** Asz print("@W: m_fifo_sync only supports power of 2 size") print(" forcing size (depth) to %d instread of " % (N, fbus.size)) wptr = Signal(modbv(0, min=0, max=N)) rptr = Signal(modbv(0, min=0, max=N)) _vld = Signal(False) # generic memory model g_fifomem = m_fifo_mem_generic(clock, fbus.wr, fbus.wdata, wptr, clock, fbus.rdata, rptr, mem_size=fbus.size) # @todo: almost full and almost empty flags read = fbus.rd write = fbus.wr @always_seq(clock.posedge, reset=reset) def rtl_fifo(): if fbus.clear: wptr.next = 0 rptr.next = 0 fbus.full.next = False fbus.empty.next = True elif read and not write: fbus.full.next = False if not fbus.empty: rptr.next = rptr + 1 if rptr == (wptr - 1): fbus.empty.next = True elif write and not read: fbus.empty.next = False if not fbus.full: wptr.next = wptr + 1 if wptr == (rptr - 1): fbus.full.next = True elif write and read: wptr.next = wptr + 1 rptr.next = rptr + 1 _vld.next = read @always_comb def rtl_assign(): fbus.rvld.next = _vld & fbus.rd nvacant = Signal(intbv(N, min=-0, max=N + 1)) # # empty slots ntenant = Signal(intbv(0, min=-0, max=N + 1)) # # filled slots @always_seq(clock.posedge, reset=reset) def dbg_occupancy(): if fbus.clear: nvacant.next = N ntenant.next = 0 else: v = nvacant f = ntenant if fbus.rvld: v = v + 1 f = f - 1 if fbus.wr: v = v - 1 f = f + 1 nvacant.next = v ntenant.next = f fbus.count = ntenant return (g_fifomem, rtl_fifo, rtl_assign, dbg_occupancy)