def _split_mem(self, mem): depths = [1 << i for i in range(log2_int(mem.depth, need_pow2=False)) if mem.depth & (1 << i)] depths.reverse() inits = None if mem.init is not None: inits = list(mem.init) mems = [] for i, depth in enumerate(depths): init = None if inits is not None: init = inits[:depth] del inits[:depth] name = "{}_part{}".format(mem.name_override, i) mems.append(Memory(width=mem.width, depth=depth, init=init, name=name)) ports = [] comb = [] sync = {} for port in mem.ports: p, c, s = self._split_port(port, mems) ports += p comb += c sy = sync.setdefault(port.clock.cd, []) sy += s return mems + ports, comb, sync
def transform_fragment(self, i, f): old_specials, f.specials = f.specials, set() old_ports = set() for old in old_specials: if not isinstance(old, Memory): f.specials.add(old) continue try: log2_int(old.depth, need_pow2=True) f.specials.add(old) except ValueError: new, comb, sync = self._split_mem(old) old_ports |= set(old.ports) f.specials.update(new) f.comb += comb for cd, sy in sync.items(): s = f.sync.setdefault(cd, []) s += sy f.specials -= old_ports
def __init__(self, width, depth): super().__init__(width, depth) ### depth_bits = log2_int(depth, True) produce = ClockDomainsRenamer("write")(GrayCounter(depth_bits + 1)) consume = ClockDomainsRenamer("read")(GrayCounter(depth_bits + 1)) self.submodules += produce, consume self.comb += [ produce.ce.eq(self.writable & self.we), consume.ce.eq(self.readable & self.re) ] produce_rdomain = Signal(depth_bits + 1) self.specials += [ NoRetiming(produce.q), MultiReg(produce.q, produce_rdomain, "read") ] consume_wdomain = Signal(depth_bits + 1) self.specials += [ NoRetiming(consume.q), MultiReg(consume.q, consume_wdomain, "write") ] if depth_bits == 1: self.comb += self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2])) else: self.comb += [ self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2]) | (produce.q[:-2] != consume_wdomain[:-2])) ] self.comb += self.readable.eq(consume.q != produce_rdomain) storage = Memory(self.width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, clock_domain="write") self.specials += wrport self.comb += [ wrport.adr.eq(produce.q_binary[:-1]), wrport.dat_w.eq(self.din), wrport.we.eq(produce.ce) ] rdport = storage.get_port(clock_domain="read") self.specials += rdport self.comb += [ rdport.adr.eq(consume.q_next_binary[:-1]), self.dout.eq(rdport.dat_r) ]
def __init__(self, width, depth): super().__init__(width, depth) ### depth_bits = log2_int(depth, True) produce = ClockDomainsRenamer("write")(GrayCounter(depth_bits + 1)) consume = ClockDomainsRenamer("read")(GrayCounter(depth_bits + 1)) self.submodules += produce, consume self.comb += [ produce.ce.eq(self.writable & self.we), consume.ce.eq(self.readable & self.re) ] produce_rdomain = Signal(depth_bits + 1) produce.q.attr.add("no_retiming") self.specials += MultiReg(produce.q, produce_rdomain, "read") consume_wdomain = Signal(depth_bits + 1) consume.q.attr.add("no_retiming") self.specials += MultiReg(consume.q, consume_wdomain, "write") if depth_bits == 1: self.comb += self.writable.eq( (produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2])) else: self.comb += [ self.writable.eq( (produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2]) | (produce.q[:-2] != consume_wdomain[:-2])) ] self.comb += self.readable.eq(consume.q != produce_rdomain) storage = Memory(self.width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, clock_domain="write") self.specials += wrport self.comb += [ wrport.adr.eq(produce.q_binary[:-1]), wrport.dat_w.eq(self.din), wrport.we.eq(produce.ce) ] rdport = storage.get_port(clock_domain="read") self.specials += rdport self.comb += [ rdport.adr.eq(consume.q_next_binary[:-1]), self.dout.eq(rdport.dat_r) ]