def __init__(self, width, depth): self.din = Signal(width) self.dout = Signal(width) self.re = Signal() ### produce = Signal(max=depth) consume = Signal(max=depth) storage = Memory(width, depth) self.specials += storage wrport = storage.get_port(write_capable=True) self.comb += [ wrport.adr.eq(produce), wrport.dat_w.eq(self.din), wrport.we.eq(1) ] self.sync += _inc(produce, depth) rdport = storage.get_port(async_read=True) self.comb += [ rdport.adr.eq(consume), self.dout.eq(rdport.dat_r) ] self.sync += If(self.re, _inc(consume, depth))
def get_fragment(self): mem = Memory(self._dw, self._depth) wp = mem.get_port(write_capable=True) rp = mem.get_port() comb = [ If(self._reg_wc.field.r != 0, self.endpoints["sink"].ack.eq(1), If(self.endpoints["sink"].stb, self._reg_wa.field.we.eq(1), self._reg_wc.field.we.eq(1), wp.we.eq(1) ) ), self._reg_wa.field.w.eq(self._reg_wa.field.r + 1), self._reg_wc.field.w.eq(self._reg_wc.field.r - 1), wp.adr.eq(self._reg_wa.field.r), wp.dat_w.eq(Cat(*self.token("sink").flatten())), rp.adr.eq(self._reg_ra.field.r), self._reg_rd.field.w.eq(rp.dat_r) ] return Fragment(comb, specials={mem})
def __init__(self, width, depth, fwft=True): super().__init__(width, depth) self.level = Signal(max=depth + 1) self.replace = Signal() ### produce = Signal(max=depth) consume = Signal(max=depth) storage = Memory(self.width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, mode=READ_FIRST) self.specials += wrport self.comb += [ If( self.replace, wrport.adr.eq(produce - 1) ).Else( wrport.adr.eq(produce) ), wrport.dat_w.eq(self.din), wrport.we.eq(self.we & (self.writable | self.replace)) ] self.sync += If(self.we & self.writable & ~self.replace, _inc(produce, depth)) do_read = Signal() self.comb += do_read.eq(self.readable & self.re) rdport = storage.get_port(async_read=fwft, has_re=not fwft, mode=READ_FIRST) self.specials += rdport self.comb += [ rdport.adr.eq(consume), self.dout.eq(rdport.dat_r) ] if not fwft: self.comb += rdport.re.eq(do_read) self.sync += If(do_read, _inc(consume, depth)) self.sync += \ If( self.we & self.writable & ~self.replace, If(~do_read, self.level.eq(self.level + 1)) ).Elif( do_read, self.level.eq(self.level - 1) ) self.comb += [ self.writable.eq(self.level != depth), self.readable.eq(self.level != 0) ]
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) ]
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
class SRAM: def __init__(self, mem_or_size, bus=None): if isinstance(mem_or_size, Memory): assert(mem_or_size.width <= 32) self.mem = mem_or_size else: self.mem = Memory(32, mem_or_size//4) if bus is None: bus = Interface() self.bus = bus def get_fragment(self): # memory port = self.mem.get_port(write_capable=True, we_granularity=8) # generate write enable signal comb = [port.we[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i]) for i in range(4)] # address and data comb += [ port.adr.eq(self.bus.adr[:len(port.adr)]), port.dat_w.eq(self.bus.dat_w), self.bus.dat_r.eq(port.dat_r) ] # generate ack sync = [ self.bus.ack.eq(0), If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1) ) ] return Fragment(comb, sync, specials={self.mem})
def __init__(self, mem_or_size, address, read_only=None, bus=None): if isinstance(mem_or_size, Memory): self.mem = mem_or_size else: self.mem = Memory(data_width, mem_or_size//(data_width//8)) self.address = address if self.mem.width > data_width: self.csrw_per_memw = (self.mem.width + data_width - 1)//data_width self.word_bits = bits_for(self.csrw_per_memw-1) else: self.csrw_per_memw = 1 self.word_bits = 0 page_bits = _compute_page_bits(self.mem.depth + self.word_bits) if page_bits: self._page = RegisterField(self.mem.name_override + "_page", page_bits) else: self._page = None if read_only is None: if hasattr(self.mem, "bus_read_only"): read_only = self.mem.bus_read_only else: read_only = False self.read_only = read_only if bus is None: bus = Interface() self.bus = bus
def __init__(self, width, depth): _FIFOInterface.__init__(self, width, depth) ### depth_bits = log2_int(depth, True) produce = GrayCounter(depth_bits+1) self.add_submodule(produce, "write") consume = GrayCounter(depth_bits+1) self.add_submodule(consume, "read") 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") ] self.comb += [ self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2]) | (produce.q[:-2] != consume_wdomain[:-2])), self.readable.eq(consume.q != produce_rdomain) ] storage = Memory(width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, clock_domain="write") 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.comb += [ rdport.adr.eq(consume.q_binary[:-1]), self.dout.eq(rdport.dat_r) ]
def __init__(self, mem_or_size, bus=None): if isinstance(mem_or_size, Memory): assert(mem_or_size.width <= 32) self.mem = mem_or_size else: self.mem = Memory(32, mem_or_size//4) if bus is None: bus = Interface() self.bus = bus
def __init__(self, width, depth): _FIFOInterface.__init__(self, width, depth) ### do_write = Signal() do_read = Signal() self.comb += [ do_write.eq(self.writable & self.we), do_read.eq(self.readable & self.re) ] level = Signal(max=depth+1) produce = Signal(max=depth) consume = Signal(max=depth) storage = Memory(width, depth) self.specials += storage wrport = storage.get_port(write_capable=True) self.comb += [ wrport.adr.eq(produce), wrport.dat_w.eq(self.din), wrport.we.eq(do_write) ] self.sync += If(do_write, _inc(produce, depth)) rdport = storage.get_port(async_read=True) self.comb += [ rdport.adr.eq(consume), self.dout.eq(rdport.dat_r) ] self.sync += If(do_read, _inc(consume, depth)) self.sync += [ If(do_write, If(~do_read, level.eq(level + 1)) ).Elif(do_read, level.eq(level - 1) ) ] self.comb += [ self.writable.eq(level != depth), self.readable.eq(level != 0) ]
def __init__(self, width, depth, idomain, odomain): self.din = Signal(width) self.dout = Signal(width) # # # reset = Signal() cd_write = ClockDomain() cd_read = ClockDomain() self.comb += [ cd_write.clk.eq(ClockSignal(idomain)), cd_read.clk.eq(ClockSignal(odomain)), reset.eq(ResetSignal(idomain) | ResetSignal(odomain)) ] self.specials += [ AsyncResetSynchronizer(cd_write, reset), AsyncResetSynchronizer(cd_read, reset) ] self.clock_domains += cd_write, cd_read wrpointer = Signal(max=depth, reset=depth//2) rdpointer = Signal(max=depth) storage = Memory(width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, clock_domain="write") rdport = storage.get_port(clock_domain="read") self.specials += wrport, rdport self.sync.write += wrpointer.eq(wrpointer + 1) self.sync.read += rdpointer.eq(rdpointer + 1) self.comb += [ wrport.we.eq(1), wrport.adr.eq(wrpointer), wrport.dat_w.eq(self.din), rdport.adr.eq(rdpointer), self.dout.eq(rdport.dat_r) ]
def __init__(self): self.n_value = n_value = len(value_input) self.index = index = Signal(5) self.data_out = Signal(32) self.type_out = Signal(2) n_type = len(value_type) assert n_value == n_type table1 = Memory(32, n_type, init=Array(value_input), name="INPUT") self.specials += table1 wrport1 = table1.get_port(write_capable=False, mode=READ_FIRST) self.specials += wrport1 table2 = Memory(2, n_type, init=Array(value_type), name="TYPE") self.specials += table2 wrport2 = table2.get_port(write_capable=False, mode=READ_FIRST) self.specials += wrport2 self.comb += [ wrport1.adr.eq(index), wrport2.adr.eq(index), self.data_out.eq(wrport1.dat_r), self.type_out.eq(wrport2.dat_r), ]
def transform_fragment(self, i, f): newspecials = set() for orig in sorted(f.specials, key=lambda x: x.duid): if not isinstance(orig, Memory): newspecials.add(orig) continue global_granularity = gcd_multiple([ p.we_granularity if p.we_granularity else orig.width for p in orig.ports ]) if global_granularity == orig.width: newspecials.add(orig) # nothing to do else: newmems = [] for i in range(orig.width // global_granularity): if orig.init is None: newinit = None else: newinit = [(v >> i * global_granularity) & (2**global_granularity - 1) for v in orig.init] newmem = Memory(global_granularity, orig.depth, newinit, orig.name_override + "_grain" + str(i)) newspecials.add(newmem) newmems.append(newmem) for port in orig.ports: port_granularity = port.we_granularity if port.we_granularity else orig.width newport = _MemoryPort( adr=port.adr, dat_r=port.dat_r[i * global_granularity:(i + 1) * global_granularity] if port.dat_r is not None else None, we=port.we[i * global_granularity // port_granularity] if port.we is not None else None, dat_w=port.dat_w[i * global_granularity:(i + 1) * global_granularity] if port.dat_w is not None else None, async_read=port.async_read, re=port.re, we_granularity=0, mode=port.mode, clock_domain=port.clock.cd) newmem.ports.append(newport) newspecials.add(newport) self.replacements[orig] = newmems f.specials = newspecials for oldmem in self.replacements.keys(): f.specials -= set(oldmem.ports)
def __init__(self, layout, depth=1024): self.sink = Sink(layout) self.busy = Signal() dw = sum(len(s) for s in self.sink.payload.flatten()) self._r_wa = CSRStorage(bits_for(depth-1), write_from_dev=True) self._r_wc = CSRStorage(bits_for(depth), write_from_dev=True, atomic_write=True) self._r_ra = CSRStorage(bits_for(depth-1)) self._r_rd = CSRStatus(dw) ### mem = Memory(dw, depth) self.specials += mem wp = mem.get_port(write_capable=True) rp = mem.get_port() self.comb += [ self.busy.eq(0), If(self._r_wc.r != 0, self.sink.ack.eq(1), If(self.sink.stb, self._r_wa.we.eq(1), self._r_wc.we.eq(1), wp.we.eq(1) ) ), self._r_wa.dat_w.eq(self._r_wa.storage + 1), self._r_wc.dat_w.eq(self._r_wc.storage - 1), wp.adr.eq(self._r_wa.storage), wp.dat_w.eq(self.sink.payload.raw_bits()), rp.adr.eq(self._r_ra.storage), self._r_rd.status.eq(rp.dat_r) ]
def __init__(self, mem_or_size, address, read_only=None, bus=None): if isinstance(mem_or_size, Memory): mem = mem_or_size else: mem = Memory(data_width, mem_or_size//(data_width//8)) if mem.width > data_width: csrw_per_memw = (mem.width + data_width - 1)//data_width word_bits = bits_for(csrw_per_memw-1) else: csrw_per_memw = 1 word_bits = 0 page_bits = _compute_page_bits(mem.depth + word_bits) if page_bits: self._page = CSRStorage(page_bits, name=mem.name_override + "_page") else: self._page = None if read_only is None: if hasattr(mem, "bus_read_only"): read_only = mem.bus_read_only else: read_only = False if bus is None: bus = Interface() self.bus = bus ### self.specials += mem port = mem.get_port(write_capable=not read_only, we_granularity=data_width if not read_only and word_bits else 0) sel = Signal() sel_r = Signal() self.sync += sel_r.eq(sel) self.comb += sel.eq(self.bus.adr[9:] == address) if word_bits: word_index = Signal(word_bits) word_expanded = Signal(csrw_per_memw*data_width) self.sync += word_index.eq(self.bus.adr[:word_bits]) self.comb += [ word_expanded.eq(port.dat_r), If(sel_r, chooser(word_expanded, word_index, self.bus.dat_r, n=csrw_per_memw, reverse=True) ) ] if not read_only: self.comb += [ If(sel & self.bus.we, port.we.eq((1 << word_bits) >> self.bus.adr[:self.word_bits])), port.dat_w.eq(Replicate(self.bus.dat_w, csrw_per_memw)) ] else: self.comb += If(sel_r, self.bus.dat_r.eq(port.dat_r)) if not read_only: self.comb += [ port.we.eq(sel & self.bus.we), port.dat_w.eq(self.bus.dat_w) ] if self._page is None: self.comb += port.adr.eq(self.bus.adr[word_bits:len(port.adr)]) else: pv = self._page.storage self.comb += port.adr.eq(Cat(self.bus.adr[word_bits:len(port.adr)-len(pv)], pv))
class SRAM: def __init__(self, mem_or_size, address, read_only=None, bus=None): if isinstance(mem_or_size, Memory): self.mem = mem_or_size else: self.mem = Memory(data_width, mem_or_size//(data_width//8)) self.address = address if self.mem.width > data_width: self.csrw_per_memw = (self.mem.width + data_width - 1)//data_width self.word_bits = bits_for(self.csrw_per_memw-1) else: self.csrw_per_memw = 1 self.word_bits = 0 page_bits = _compute_page_bits(self.mem.depth + self.word_bits) if page_bits: self._page = RegisterField(self.mem.name_override + "_page", page_bits) else: self._page = None if read_only is None: if hasattr(self.mem, "bus_read_only"): read_only = self.mem.bus_read_only else: read_only = False self.read_only = read_only if bus is None: bus = Interface() self.bus = bus def get_registers(self): if self._page is None: return [] else: return [self._page] def get_fragment(self): port = self.mem.get_port(write_capable=not self.read_only, we_granularity=data_width if not self.read_only and self.word_bits else 0) sel = Signal() sel_r = Signal() sync = [sel_r.eq(sel)] comb = [sel.eq(self.bus.adr[9:] == self.address)] if self.word_bits: word_index = Signal(self.word_bits) word_expanded = Signal(self.csrw_per_memw*data_width) sync.append(word_index.eq(self.bus.adr[:self.word_bits])) comb += [ word_expanded.eq(port.dat_r), If(sel_r, chooser(word_expanded, word_index, self.bus.dat_r, n=self.csrw_per_memw, reverse=True) ) ] if not self.read_only: comb += [ If(sel & self.bus.we, port.we.eq((1 << self.word_bits) >> self.bus.adr[:self.word_bits])), port.dat_w.eq(Replicate(self.bus.dat_w, self.csrw_per_memw)) ] else: comb += [ If(sel_r, self.bus.dat_r.eq(port.dat_r) ) ] if not self.read_only: comb += [ port.we.eq(sel & self.bus.we), port.dat_w.eq(self.bus.dat_w) ] if self._page is None: comb.append(port.adr.eq(self.bus.adr[self.word_bits:len(port.adr)])) else: pv = self._page.field.r comb.append(port.adr.eq(Cat(self.bus.adr[self.word_bits:len(port.adr)-len(pv)], pv))) return Fragment(comb, sync, specials={self.mem})
from migen.fhdl.structure import Fragment from migen.fhdl.specials import Memory from migen.fhdl import verilog mem = Memory(32, 100, init=[5, 18, 32]) p1 = mem.get_port(write_capable=True, we_granularity=8) p2 = mem.get_port(has_re=True, clock_domain="rd") f = Fragment(specials={mem}) v = verilog.convert(f, ios={p1.adr, p1.dat_r, p1.we, p1.dat_w, p2.adr, p2.dat_r, p2.re}) print(v)
def get_fragment(self): comb = [] sync = [] aaw = self.asmiport.hub.aw adw = self.asmiport.hub.dw # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(adw//32) addressbits = aaw + offsetbits linebits = log2_int(self.cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(adw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) write_from_asmi = Signal() write_to_asmi = Signal() adr_offset_r = Signal(offsetbits) comb += [ data_port.adr.eq(adr_line), If(write_from_asmi, data_port.dat_w.eq(self.asmiport.dat_r), data_port.we.eq(Replicate(1, adw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, adw//32)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_asmi, self.asmiport.dat_w.eq(data_port.dat_r)), self.asmiport.dat_wm.eq(0), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] sync += [ adr_offset_r.eq(adr_offset) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) tag_do = Record(tag_layout) tag_di = Record(tag_layout) comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), self.asmiport.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM write_to_asmi_pre = Signal() sync.append(write_to_asmi.eq(write_to_asmi_pre)) fsm = FSM("IDLE", "TEST_HIT", "EVICT_ISSUE", "EVICT_WAIT", "REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE") fsm.act(fsm.IDLE, If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT)) ) fsm.act(fsm.TEST_HIT, If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), fsm.next_state(fsm.IDLE) ).Else( If(tag_do.dirty, fsm.next_state(fsm.EVICT_ISSUE) ).Else( fsm.next_state(fsm.REFILL_WRTAG) ) ) ) fsm.act(fsm.EVICT_ISSUE, self.asmiport.stb.eq(1), self.asmiport.we.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.EVICT_WAIT)) ) fsm.act(fsm.EVICT_WAIT, # Data is actually sampled by the memory controller in the next state. # But since the data memory has one cycle latency, it gets the data # at the address given during this cycle. If(self.asmiport.get_call_expression(), write_to_asmi_pre.eq(1), fsm.next_state(fsm.REFILL_WRTAG) ) ) fsm.act(fsm.REFILL_WRTAG, # Write the tag first to set the ASMI address tag_port.we.eq(1), fsm.next_state(fsm.REFILL_ISSUE) ) fsm.act(fsm.REFILL_ISSUE, self.asmiport.stb.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.REFILL_WAIT)) ) fsm.act(fsm.REFILL_WAIT, If(self.asmiport.get_call_expression(), fsm.next_state(fsm.REFILL_COMPLETE)) ) fsm.act(fsm.REFILL_COMPLETE, write_from_asmi.eq(1), fsm.next_state(fsm.TEST_HIT) ) return Fragment(comb, sync, specials={data_mem, tag_mem}) \ + fsm.get_fragment()