AxiFifoAdapter.scala 5.18 KB
Newer Older
1
package chisel.axiutils
2
3
import  chisel.axi._
import  chisel.miscutils.Logging
Jens Korinth's avatar
Jens Korinth committed
4
5
import  chisel3._
import  chisel3.util._
6

7
8
9
10
11
12
13
14
15
16
17
object AxiFifoAdapter {
  /**
   * Configuration parameters for AxiFifoAdapter.
   * @param axi AXI-MM interface parameters.
   * @param fifoDepth Depth of the backing FIFO (each element data width wide).
   * @param burstSize Number of beats per burst (optional).
   * @param size Address wrap-around after size elements (optional).
   **/
  sealed case class Configuration(fifoDepth: Int,
                                  burstSize: Option[Int] = None,
                                  size: Option[Int] = None)
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
  /**
   * I/O bundle for AxiFifoAdapter.
   **/
  class IO(cfg: Configuration)(implicit axi: Axi4.Configuration) extends Bundle {
    val maxi = Axi4.Master(axi)
    val deq  = Decoupled(UInt(axi.dataWidth))
    val base = Input(UInt(axi.addrWidth))
  }

  /**
   * Build an AxiFifoAdapter.
   * @param cfg Configuration.
   * @return AxiFifoAdapter instance.
   **/
  def apply(cfg: Configuration)(implicit axi: Axi4.Configuration, l: Logging.Level): AxiFifoAdapter =
    new AxiFifoAdapter(cfg)

  /**
   * Build an AxiFifoAdapter.
   * @param fifoDepth Depth of the backing FIFO (each element data width wide).
   * @param burstSize Number of beats per burst (optional).
   * @param size Address wrap-around after size elements (optional).
   * @return AxiFifoAdapter instance.
   **/
  def apply(fifoDepth: Int,
            burstSize: Option[Int] = None,
            size: Option[Int] = None)
           (implicit axi: Axi4.Configuration, l: Logging.Level): AxiFifoAdapter =
    new AxiFifoAdapter(Configuration(fifoDepth = fifoDepth, burstSize = burstSize, size = size))
48
}
Jens Korinth's avatar
Jens Korinth committed
49

50
51
52
53
54
55
/**
 * AxiFifoAdapter is simple DMA engine filling a FIFO via AXI-MM master.
 * The backing FIFO is filled continuosly with burst via the master
 * interface; the FIFO itself uses handshakes for consumption.
 * @param cfg Configuration parameters.
 **/
56
57
58
class AxiFifoAdapter(cfg: AxiFifoAdapter.Configuration)
                    (implicit axi: Axi4.Configuration,
                     logLevel: Logging.Level) extends Module with Logging{
59
  val bsz = cfg.burstSize.getOrElse(cfg.fifoDepth)
Jens Korinth's avatar
Jens Korinth committed
60

Jens Korinth's avatar
Jens Korinth committed
61
62
63
  require (cfg.size.map(s => log2Ceil(s) <= axi.addrWidth).getOrElse(true),
           "addrWidth (%d) must be large enough to address all %d elements, at least %d bits"
           .format(axi.addrWidth:Int, cfg.size.get, log2Ceil(cfg.size.get)))
64
  require (cfg.size.isEmpty,
Jens Korinth's avatar
Jens Korinth committed
65
           "size parameter is not implemented")
66
  require (bsz > 0 && bsz <= cfg.fifoDepth && bsz <= 256,
Jens Korinth's avatar
Jens Korinth committed
67
           "burst size (%d) must be 0 < bsz <= FIFO depth (%d) <= 256"
68
           .format(bsz, cfg.fifoDepth))
Jens Korinth's avatar
Jens Korinth committed
69

70
71
72
73
  cinfo ("AxiFifoAdapter: fifoDepth = %d, address bits = %d, data bits = %d, id bits = %d%s%s"
         .format(cfg.fifoDepth, axi.addrWidth:Int, axi.dataWidth:Int, axi.idWidth:Int,
                 cfg.burstSize.map(", burst size = %d".format(_)).getOrElse(""),
                 cfg.size.map(", size = %d".format(_)).getOrElse("")))
Jens Korinth's avatar
Jens Korinth committed
74

75
  val io = IO(new AxiFifoAdapter.IO(cfg))
Jens Korinth's avatar
Jens Korinth committed
76

Jens Korinth's avatar
Jens Korinth committed
77
78
79
80
81
  val axi_read :: axi_wait :: Nil = Enum(2)

  val fifo  = Module(new Queue(UInt(axi.dataWidth), cfg.fifoDepth))
  val state = RegInit(axi_wait)
  val len   = Reg(UInt(log2Ceil(bsz).W))
82
83
  val ra_hs = Reg(Bool())

Jens Korinth's avatar
Jens Korinth committed
84
85
  val maxi_rlast   = io.maxi.readData.bits.last
  val maxi_raddr   = RegInit(io.base)
86
  val maxi_ravalid = !reset && state === axi_read && !ra_hs
Jens Korinth's avatar
Jens Korinth committed
87
  val maxi_raready = io.maxi.readAddr.ready
Jens Korinth's avatar
Jens Korinth committed
88
89
  val maxi_rready  = !reset && state === axi_read && fifo.io.enq.ready
  val maxi_rvalid  = state === axi_read && io.maxi.readData.valid
Jens Korinth's avatar
Jens Korinth committed
90

Jens Korinth's avatar
Jens Korinth committed
91
92
93
94
95
  io.deq                            <> fifo.io.deq
  fifo.io.enq.bits                  := io.maxi.readData.bits.data
  io.maxi.readData.ready            := maxi_rready
  io.maxi.readAddr.valid            := maxi_ravalid
  fifo.io.enq.valid                 := io.maxi.readData.valid
Jens Korinth's avatar
Jens Korinth committed
96
97

  // AXI boilerplate
Jens Korinth's avatar
Jens Korinth committed
98
99
100
101
102
103
104
105
106
  io.maxi.readAddr.bits.addr        := maxi_raddr
  io.maxi.readAddr.bits.burst.size  := (if (axi.dataWidth > 8) log2Ceil(axi.dataWidth / 8) else 0).U
  io.maxi.readAddr.bits.burst.len   := (bsz - 1).U
  io.maxi.readAddr.bits.burst.burst := Axi4.Burst.Type.incr
  io.maxi.readAddr.bits.id          := 0.U
  io.maxi.readAddr.bits.lock.lock   := 0.U
  io.maxi.readAddr.bits.cache.cache := Axi4.Cache.Read.WRITE_BACK_RW_ALLOCATE
  io.maxi.readAddr.bits.prot.prot   := 0.U
  io.maxi.readAddr.bits.qos         := 0.U
Jens Korinth's avatar
Jens Korinth committed
107
108

  // write channel tie-offs
Jens Korinth's avatar
Jens Korinth committed
109
110
111
  io.maxi.writeAddr.valid           := false.B
  io.maxi.writeData.valid           := false.B
  io.maxi.writeResp.ready           := false.B
112

113
  when (reset) {
114
    state       := axi_wait
Jens Korinth's avatar
Jens Korinth committed
115
    len         := (bsz - 1).U
116
    maxi_raddr  := io.base
Jens Korinth's avatar
Jens Korinth committed
117
    ra_hs       := false.B
118
119
  }
  .otherwise {
Jens Korinth's avatar
Jens Korinth committed
120
    when (state === axi_wait && fifo.io.count <= (cfg.fifoDepth - bsz).U) { state := axi_read }
Jens Korinth's avatar
Jens Korinth committed
121
    when (state === axi_read) {
122
      when (maxi_ravalid && maxi_raready) {
Jens Korinth's avatar
Jens Korinth committed
123
124
        maxi_raddr := maxi_raddr + (bsz * (axi.dataWidth / 8)).U
        ra_hs := true.B
125
      }
Jens Korinth's avatar
Jens Korinth committed
126
127
      when (maxi_rready && maxi_rvalid) {
        when (maxi_rlast) {
Jens Korinth's avatar
Jens Korinth committed
128
129
130
          state := Mux(fifo.io.count <= (cfg.fifoDepth - bsz).U, state, axi_wait)
          len := (bsz - 1).U
          ra_hs := false.B
Jens Korinth's avatar
Jens Korinth committed
131
        }
Jens Korinth's avatar
Jens Korinth committed
132
        .otherwise { len := len - 1.U }
133
134
135
136
      }
    }
  }
}