AxiFifoAdapter.scala 4.35 KB
Newer Older
1
package chisel.axiutils
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import Chisel._
import AXIDefs._

class AxiFifoAdapter(
    fifoDepth: Int,
    addrWidth: Int,
    dataWidth: Int,
    idWidth  : Int = 1
  ) extends Module {

  require (fifoDepth > 0, "FIFO depth (%d) must be > 0".format(fifoDepth))
  require (fifoDepth <= 256, "FIFO depth (%d) must be <= 256".format(fifoDepth))
  require (addrWidth > 0 && addrWidth <= 64, "AXI address width (%d) must 0 < width <= 64".format(addrWidth))
  require (dataWidth >= 8 && dataWidth <= 256, "AXI data width (%d) must be 8 <= width <= 256".format(dataWidth))
  require ((for (i <- 1 to 7) yield scala.math.pow(2, i).toInt).contains(dataWidth), "AXI data width (%d) must be a power of 2".format(dataWidth))
  require ((idWidth > 0), "AXI id width (%d) must be > 0".format(idWidth))

  val io = new Bundle {
    val maxi = new AXIMasterIF(addrWidthBits = addrWidth, dataWidthBits = dataWidth, idBits = idWidth)
    val deq  = Decoupled(UInt(width = dataWidth))
    val base = UInt(INPUT, width = addrWidth)
    maxi.renameSignals()
    base.setName("base")
  }

  val axi_fetch :: axi_wait :: Nil = Enum(UInt(), 2)
  val axi_state        = Reg(init = axi_wait)

  val fifo_a           = Module(new Queue(UInt(width = dataWidth), fifoDepth))
  val fifo_b           = Module(new Queue(UInt(width = dataWidth), fifoDepth))
  val fifo_sel         = Reg(Bool())

  io.deq.valid        := Mux(!fifo_sel, fifo_a.io.deq.valid, fifo_b.io.deq.valid)
  io.deq.bits         := Mux(!fifo_sel, fifo_a.io.deq.bits, fifo_b.io.deq.bits)
  fifo_a.io.deq.ready := !fifo_sel && io.deq.ready
  fifo_b.io.deq.ready :=  fifo_sel && io.deq.ready

  val maxi_rdata       = (io.maxi.readData.bits.data)
  val maxi_rlast       = (io.maxi.readData.bits.last)
  val maxi_rvalid      = (io.maxi.readData.valid)
  val maxi_rready      = (Mux(fifo_sel, fifo_a.io.enq.ready, fifo_b.io.enq.ready))

  fifo_a.io.enq.bits  := (maxi_rdata)
  fifo_a.io.enq.valid :=  fifo_sel && maxi_rready && maxi_rvalid

  fifo_b.io.enq.bits  := (maxi_rdata)
  fifo_b.io.enq.valid := !fifo_sel && maxi_rready && maxi_rvalid

  val maxi_raddr       = Reg(init = io.base)
  val maxi_raddr_hs    = Reg(Bool())
  val maxi_ravalid     = axi_state === axi_fetch && !maxi_raddr_hs
  val maxi_raready     = (io.maxi.readAddr.ready)

  io.maxi.readAddr.bits.addr := maxi_raddr
  io.maxi.readAddr.valid     := maxi_ravalid

  io.maxi.readAddr.bits.size := UInt(log2Up(dataWidth / 8 - 1))
59
  io.maxi.readAddr.bits.len  := UInt(fifoDepth - 1)
60
61
62
63
64
65
66
67
68
  io.maxi.readAddr.bits.burst:= UInt("b01") // INCR
  io.maxi.readAddr.bits.id   := UInt(0)
  io.maxi.readAddr.bits.lock := UInt(0)
  io.maxi.readAddr.bits.cache:= UInt("b1110") // write-through, RW alloc
  io.maxi.readAddr.bits.prot := UInt(0)
  io.maxi.readAddr.bits.qos  := UInt(0)

  io.maxi.readData.ready     := maxi_rready

69
70
71
72
73
74
75
  // true, if buffers will be empty next cycle
  val switch_a = fifo_a.io.deq.ready && fifo_a.io.count <= UInt(1)
  val switch_b = fifo_b.io.deq.ready && fifo_b.io.count <= UInt(1)
  // true, if buffer fill should start next cycle
  val fill_a = fifo_a.io.count === UInt(0) || switch_a
  val fill_b = fifo_b.io.count === UInt(0) || switch_b

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  when (reset) {
    fifo_sel          := Bool(false)
    axi_state         := axi_wait
    maxi_raddr        := UInt(0)
    maxi_raddr_hs     := Bool(false)
  }
  .otherwise {
    when (axi_state === axi_fetch) {  // fetch data state
      // handshake current address
      when (maxi_raready && maxi_ravalid) {
        maxi_raddr_hs := Bool(true)
        maxi_raddr    := maxi_raddr + UInt((dataWidth * fifoDepth) / 8)
      }
      // when read data is valid, enq fifo is ready and last is set
      when (maxi_rready && maxi_rvalid && maxi_rlast) {
91
92
93
94
95
96
97
98
99
100
101
        maxi_raddr_hs := Bool(false) // re-enable address handshake

        // check if we can stay in fetch mode and flip buffers
        when (Mux(!fifo_sel, switch_a, switch_b)) {
          // just flip buffers
          fifo_sel      := !fifo_sel
        }
        .otherwise {
          // go to wait state
          axi_state     := axi_wait
        }
102
103
104
105
      }
    }
    .otherwise { // wait-for-consumption state 
      // check fill state of deq FIFO: if empty, flip FIFOs
106
      when (Mux(!fifo_sel, switch_a, switch_b)) {
107
108
109
        fifo_sel      := !fifo_sel
      }
      // check fill state of other FIFO
110
      when (Mux(!fifo_sel, fill_b, fill_a)) {
111
112
113
114
115
116
117
        // if empty, start fetch
        axi_state     := axi_fetch
      }
    }
  }
}