DataWidthConverter.scala 3.01 KB
Newer Older
1
package chisel.miscutils
2
3
import  chisel3._
import  chisel3.util._
4

5
6
7
8
9
10
11
object DataWidthConverter {
  class IO(inWidth: Int, outWidth: Int) extends Bundle {
    val inq = Flipped(Decoupled(UInt(inWidth.W)))
    val deq = Decoupled(UInt(outWidth.W))
  }
}

12
13
14
15
16
17
18
/**
 * DataWidthConverter converts the data width of a Queue.
 * Output is provided via a Queue, with increased or decreased
 * data rate, depending on the direction of the conversion.
 * Note: This would be much more useful, if the two Queues
 *       could use different clocks, but multi-clock support
 *       in Chisel is currently unstable.
19
20
 * @param inWidth Data width of input DecoupledIO (bits).
 * @param outWidth Data width of output DecoupledIO (bits); must
21
22
23
24
 *                 be integer multiples of each other.
 * @param littleEndian if inWidth > outWidth, determines
 *                     the order of the nibbles (low to high)
 **/
25
26
class DataWidthConverter(val inWidth: Int,
                         val outWidth: Int,
27
28
                         val littleEndian: Boolean = true)
                        (implicit logLevel: Logging.Level) extends Module with Logging {
29
30
31
32
33
34
35
36
  require (inWidth > 0, "inWidth must be > 0")
  require (outWidth > 0, "inWidth must be > 0")
  require (inWidth != outWidth, "inWidth (%d) must be different from outWidth (%d)"
             .format(inWidth, outWidth))
  require (inWidth % outWidth == 0 || outWidth % inWidth == 0,
           "inWidth (%d) and outWidth (%d) must be integer multiples of each other"
             .format(inWidth, outWidth))

37
38
39
  cinfo(s"inWidth = $inWidth, outWidth = $outWidth, littleEndian = $littleEndian")

  val io = IO(new DataWidthConverter.IO(inWidth, outWidth))
40
41
42
43
44
45
46
47
48
49

  val ratio: Int = if (inWidth > outWidth) inWidth / outWidth else outWidth / inWidth
  val d_w = if (inWidth > outWidth) inWidth else outWidth // data register width

  if (inWidth > outWidth)
    downsize()
  else
    upsize()

  private def upsize() = {
50
51
    val i = RegInit(UInt(log2Ceil(ratio + 1).W), init = ratio.U)
    val d = RegInit(UInt(outWidth.W), 0.U)
52

53
    io.inq.ready := i =/= 0.U || (io.inq.valid && io.deq.ready)
54
    io.deq.bits  := d
55
    io.deq.valid := i === 0.U
56

57
58
59
60
61
62
    when (io.inq.ready && io.inq.valid) {
      if (littleEndian)
        d := Cat(io.inq.bits, d) >> inWidth.U
      else
        d := (d << inWidth.U) | io.inq.bits
      i := i - 1.U
63
    }
64
65
    when (io.deq.valid && io.deq.ready) {
      i := Mux(io.inq.valid, (ratio - 1).U, ratio.U)
66
67
68
69
    }
  }

  private def downsize() = {
70
71
    val i = RegInit(UInt(log2Ceil(ratio + 1).W), init = 0.U)
    val d = RegInit(UInt(inWidth.W), init = 0.U)
72

73
74
    io.inq.ready := i === 0.U || (i === 1.U && io.deq.ready)
    io.deq.valid := i > 0.U
75
76
77
78
79
    if (littleEndian)
      io.deq.bits := d(outWidth - 1, 0)
    else
      io.deq.bits := d(inWidth - 1, inWidth - outWidth)

80
81
82
83
84
85
    when (i > 0.U && io.deq.ready) {
      if (littleEndian)
        d := d >> outWidth.U
      else
        d := d << outWidth.U
      i := i - 1.U
86
    }
87
88
89
    when (io.inq.ready && io.inq.valid) {
      d := io.inq.bits
      i := ratio.U
90
91
92
93
    }
  }
}