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))
Example #2
0
	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})
Example #3
0
    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)
        ]
Example #4
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)
        ]
Example #5
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)
        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)
        ]
Example #6
0
 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
Example #7
0
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})
Example #8
0
	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
Example #9
0
	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)
		]
Example #10
0
	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
Example #11
0
	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)
		]
Example #12
0
File: cdc.py Project: m-labs/migen
    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, 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)
        ]
Example #14
0
    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),
        ]
Example #15
0
    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)
Example #16
0
	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)
		]
Example #17
0
	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))
Example #18
0
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})
Example #19
0
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)
Example #20
0
	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()