Skip to content

Commit f8b1152

Browse files
committedJun 17, 2015
wishbone: add Cache (from WB2LASMI)
1 parent 6e876c6 commit f8b1152

File tree

1 file changed

+159
-1
lines changed

1 file changed

+159
-1
lines changed
 

Diff for: ‎migen/bus/wishbone.py

+159-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from migen.fhdl.std import *
22
from migen.genlib import roundrobin
33
from migen.genlib.record import *
4-
from migen.genlib.misc import optree, chooser, FlipFlop, Counter
4+
from migen.genlib.misc import split, displacer, optree, chooser
5+
from migen.genlib.misc import FlipFlop, Counter
56
from migen.genlib.fsm import FSM, NextState
7+
from migen.bank.description import *
68
from migen.bus.transactions import *
79

810
_layout = [
@@ -407,6 +409,162 @@ def __init__(self, master, slave):
407409
Record.connect(master, slave)
408410

409411

412+
class Cache(Module, AutoCSR):
413+
"""Cache
414+
415+
This module is a write-back wishbone cache that can be used as a L2 cache.
416+
Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
417+
"""
418+
def __init__(self, cachesize, master, slave):
419+
self._size = CSRStatus(8, reset=log2_int(cachesize))
Has conversations. Original line has conversations.
420+
self.master = master
421+
self.slave = slave
422+
423+
###
424+
425+
dw_from = flen(master.dat_r)
426+
dw_to = flen(slave.dat_r)
427+
if dw_to > dw_from and (dw_to % dw_from) != 0:
428+
raise ValueError("Slave data width must be a multiple of {dw}".format(dw=dw_from))
429+
if dw_to < dw_from and (dw_from % dw_to) != 0:
430+
raise ValueError("Master data width must be a multiple of {dw}".format(dw=dw_to))
431+
432+
# Split address:
433+
# TAG | LINE NUMBER | LINE OFFSET
434+
offsetbits = log2_int(max(dw_to//dw_from, 1))
435+
addressbits = flen(slave.adr) + offsetbits
436+
linebits = log2_int(cachesize) - offsetbits
437+
tagbits = addressbits - linebits
438+
wordbits = log2_int(max(dw_from//dw_to, 1))
439+
adr_offset, adr_line, adr_tag = split(master.adr, offsetbits, linebits, tagbits)
440+
word = Signal(wordbits) if wordbits else None
441+
442+
# Data memory
443+
data_mem = Memory(dw_to*2**wordbits, 2**linebits)
444+
data_port = data_mem.get_port(write_capable=True, we_granularity=8)
445+
self.specials += data_mem, data_port
446+
447+
write_from_slave = Signal()
448+
if adr_offset is None:
449+
adr_offset_r = None
450+
else:
451+
adr_offset_r = Signal(offsetbits)
452+
self.sync += adr_offset_r.eq(adr_offset)
453+
454+
self.comb += [
455+
data_port.adr.eq(adr_line),
456+
If(write_from_slave,
457+
displacer(slave.dat_r, word, data_port.dat_w),
458+
displacer(Replicate(1, dw_to//8), word, data_port.we)
459+
).Else(
460+
data_port.dat_w.eq(Replicate(master.dat_w, max(dw_to//dw_from, 1))),
461+
If(master.cyc & master.stb & master.we & master.ack,
462+
displacer(master.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True)
463+
)
464+
),
465+
chooser(data_port.dat_r, word, slave.dat_w),
466+
slave.sel.eq(2**(dw_to//8)-1),
467+
chooser(data_port.dat_r, adr_offset_r, master.dat_r, reverse=True)
468+
]
469+
470+
471+
# Tag memory
472+
tag_layout = [("tag", tagbits), ("dirty", 1)]
473+
tag_mem = Memory(layout_len(tag_layout), 2**linebits)
474+
tag_port = tag_mem.get_port(write_capable=True)
475+
self.specials += tag_mem, tag_port
476+
tag_do = Record(tag_layout)
477+
tag_di = Record(tag_layout)
478+
self.comb += [
479+
tag_do.raw_bits().eq(tag_port.dat_r),
480+
tag_port.dat_w.eq(tag_di.raw_bits())
481+
]
482+
483+
self.comb += [
484+
tag_port.adr.eq(adr_line),
485+
tag_di.tag.eq(adr_tag)
486+
]
487+
if word is not None:
488+
self.comb += slave.adr.eq(Cat(word, adr_line, tag_do.tag))
489+
else:
490+
self.comb += slave.adr.eq(Cat(adr_line, tag_do.tag))
491+
492+
# slave word computation, word_clr and word_inc will be simplified
493+
# at synthesis when wordbits=0
494+
word_clr = Signal()
495+
word_inc = Signal()
496+
if word is not None:
497+
self.sync += \
498+
If(word_clr,
499+
word.eq(0),
500+
).Elif(word_inc,
501+
word.eq(word+1)
502+
)
503+
504+
def word_is_last(word):
505+
if word is not None:
506+
return word == 2**wordbits-1
507+
else:
508+
return 1
509+
510+
# Control FSM
511+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
512+
fsm.act("IDLE",
513+
If(master.cyc & master.stb,
514+
NextState("TEST_HIT")
515+
)
516+
)
517+
fsm.act("TEST_HIT",
518+
word_clr.eq(1),
519+
If(tag_do.tag == adr_tag,
520+
master.ack.eq(1),
521+
If(master.we,
522+
tag_di.dirty.eq(1),
523+
tag_port.we.eq(1)
524+
),
525+
NextState("IDLE")
526+
).Else(
527+
If(tag_do.dirty,
528+
NextState("EVICT")
529+
).Else(
530+
NextState("REFILL_WRTAG")
531+
)
532+
)
533+
)
534+
535+
fsm.act("EVICT",
536+
slave.stb.eq(1),
537+
slave.cyc.eq(1),
538+
slave.we.eq(1),
539+
If(slave.ack,
540+
word_inc.eq(1),
541+
If(word_is_last(word),
542+
NextState("REFILL_WRTAG")
543+
)
544+
)
545+
)
546+
fsm.act("REFILL_WRTAG",
547+
# Write the tag first to set the slave address
548+
tag_port.we.eq(1),
549+
word_clr.eq(1),
550+
NextState("REFILL")
551+
)
552+
fsm.act("REFILL",
553+
slave.stb.eq(1),
554+
slave.cyc.eq(1),
555+
slave.we.eq(0),
556+
If(slave.ack,
557+
write_from_slave.eq(1),
558+
word_inc.eq(1),
559+
If(word_is_last(word),
560+
NextState("TEST_HIT"),
561+
).Else(
562+
NextState("REFILL")
563+
)
564+
)
565+
)
566+
567+
410568
class Tap(Module):
411569
def __init__(self, bus, handler=print):
412570
self.bus = bus

0 commit comments

Comments
 (0)
Please sign in to comment.