|
1 | 1 | from migen.fhdl.std import *
|
2 | 2 | from migen.genlib import roundrobin
|
3 | 3 | 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 |
5 | 6 | from migen.genlib.fsm import FSM, NextState
|
| 7 | +from migen.bank.description import * |
6 | 8 | from migen.bus.transactions import *
|
7 | 9 |
|
8 | 10 | _layout = [
|
@@ -407,6 +409,162 @@ def __init__(self, master, slave):
|
407 | 409 | Record.connect(master, slave)
|
408 | 410 |
|
409 | 411 |
|
| 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 | + |
410 | 568 | class Tap(Module):
|
411 | 569 | def __init__(self, bus, handler=print):
|
412 | 570 | self.bus = bus
|
|