RegisterFile.scala 8.14 KB
Newer Older
Jens Korinth's avatar
Jens Korinth committed
1
package chisel.axi.axi4lite
Jens Korinth's avatar
Jens Korinth committed
2
3
4
5
6
import  chisel.axi._, chisel.axi.Axi4Lite
import  chisel.miscutils.Logging
import  chisel3._
import  chisel3.util._
import  scala.util.Properties.{lineSeparator => NL}
7
import  org.scalactic.anyvals.PosInt
Jens Korinth's avatar
Jens Korinth committed
8
9
10

object RegisterFile {
  /** Configuration object for RegisterFiles.
11
   *  @param addressWordBits Smallest addressable bit width (default: 8, e.g., 1 byte).
Jens Korinth's avatar
Jens Korinth committed
12
13
14
   *  @param width Register data width (in bits).
   *  @param regs Map from offsets in addrGranularity to register implementations.
   **/
15
  case class Configuration(addressWordBits: Int = 8, regs: Map[Int, ControlRegister], fifoDepth: PosInt = 2)
Jens Korinth's avatar
Jens Korinth committed
16
17
18
19
                          (implicit axi: Axi4Lite.Configuration) {
    /* internal helpers: */
    private def overlap(p: (BitRange, BitRange)) = p._1.overlapsWith(p._2)
    private def makeRange(a: Int): BitRange =
20
      BitRange(a * addressWordBits + axi.dataWidth.toInt - 1, a * addressWordBits)
Jens Korinth's avatar
Jens Korinth committed
21
    private lazy val m = regs.keys.toList.sorted map makeRange
22
23
    private lazy val o = (m.take(m.length - 1) zip m.tail) map { case (r1, r2) => ((r1, r2), r1.overlapsWith(r2)) }
    o filter (_._2) foreach { case ((r1, r2), _) => require(!r1.overlapsWith(r2), s"$r1 and $r2 must not overlap") }
Jens Korinth's avatar
Jens Korinth committed
24
25
26

    /* constraint checking */
    require (regs.size > 0, "regs must not be empty")
27
    require (regs.size == 1 || !(o map (_._2) reduce (_ || _)), "ranges must not overlap: " + regs)
Jens Korinth's avatar
Jens Korinth committed
28
29

    /** Minimum bit width of address lines. */
30
    lazy val minAddrWidth: AddrWidth = AddrWidth(Seq(if (regs.size * axi.dataWidth.toInt >= regs.keys.max) {
31
      log2Ceil((regs.size * axi.dataWidth.toInt) / addressWordBits)
32
33
34
    } else {
      log2Ceil(regs.keys.max)
    }, 1).max)
Jens Korinth's avatar
Jens Korinth committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

    /** Dumps address map as markdown file. **/
    def dumpAddressMap(path: String) = {
      def mksz(s: String, w: Int) = if (s.length > w) s.take(w) else if (s.length < w) s + (" " * (w - s.length)) else s
      val fw = new java.io.FileWriter(java.nio.file.Paths.get(path).resolve("AdressMap.md").toString)
      fw.append("| **Name**        |**From**|**To**  | **Description**                          |").append(NL)
        .append("|:----------------|:------:|:------:|:-----------------------------------------|").append(NL)
      for (off <- regs.keys.toList.sorted; reg = regs(off))
        fw.append("| %s | 0x%04x | 0x%04x | %s |".format(
          mksz(reg.name.getOrElse("N/A"), 15), off, off + axi.dataWidth / 8 - 1, reg.description
        )).append(NL)
      fw.flush()
      fw.close
    }
  }

  /**
   * Axi4LiteRegisterFile bundle.
   * @param cfg [[Configuration]] object.
   * @param axi Implicit AXI configuration.
   **/
  class IO(cfg: Configuration)(implicit axi: Axi4Lite.Configuration) extends Bundle {
    val addrWidth: AddrWidth = AddrWidth(Seq(cfg.minAddrWidth:Int, axi.addrWidth:Int).max)
    val saxi = Axi4Lite.Slave(axi)
59
60

    override def cloneType = new IO(cfg)(axi).asInstanceOf[this.type]
Jens Korinth's avatar
Jens Korinth committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  }
}

/**
 * RegisterFile implements a AXI4Lite register file:
 * Writes currently take at least 3 cycles (addr -> data -> response), reads at
 * least 2 (addr -> response). No strobe support, always read/write full register
 * width.
 * @param cfg Configuration object.
 * @param axi Implicit AXI configuration.
 **/
class RegisterFile(cfg: RegisterFile.Configuration)
                  (implicit axi: Axi4Lite.Configuration,
                   logLevel: Logging.Level) extends Module with Logging {
75
76
  class ReadData extends Bundle {
    val data = io.saxi.readData.bits.data.cloneType
77
    val resp = io.saxi.readData.bits.resp.cloneType
78
    override def cloneType = (new ReadData).asInstanceOf[this.type]
79
  }
Jens Korinth's avatar
Jens Korinth committed
80

81
  val io = IO(new RegisterFile.IO(cfg))
Jens Korinth's avatar
Jens Korinth committed
82

83
84
85
86
87
88
89
90
91
  // workaround: code below does not work due to optional elements in bundle
  //val in_q_ra  = Queue(io.saxi.readAddr,  entries = cfg.fifoDepth, pipe = true)
  val in_q_ra = Module(new Queue(io.saxi.readAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
  //val in_q_wa  = Queue(io.saxi.writeAddr, entries = cfg.fifoDepth, pipe = true)
  val in_q_wa = Module(new Queue(io.saxi.writeAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
  //val in_q_wd  = Queue(io.saxi.writeData, entries = cfg.fifoDepth, pipe = true)
  val in_q_wd = Module(new Queue(io.saxi.writeData.bits.data.cloneType, entries = cfg.fifoDepth, pipe = true))

  val read_reg = Reg((new ReadData).cloneType)
92
  val resp_reg = RegNext(Response.slverr, init = Response.slverr)
93
94
95
96
97
98

  //val out_q_rd = Module(new Queue(new Axi4Lite.Data.Read, cfg.fifoDepth))
  val out_q_rd = Module(new Queue((new ReadData).cloneType, cfg.fifoDepth))
  //val out_q_wr = Module(new Queue(new Axi4Lite.WriteResponse, cfg.fifoDepth))
  val out_q_wr = Module(new Queue(io.saxi.writeResp.bits.bresp.cloneType, cfg.fifoDepth))

99
100
101
102
103
104
105
  /*when (in_q_ra.io.enq.fire)  { info(p"received read address: 0x${Hexadecimal(in_q_ra.io.enq.bits)} (${in_q_ra.io.enq.bits})") }
  when (in_q_wa.io.enq.fire)  { info(p"received write address: 0x${Hexadecimal(in_q_wa.io.enq.bits)} (${in_q_wa.io.enq.bits})") }
  when (in_q_wd.io.enq.fire)  { info(p"received write data: 0x${Hexadecimal(in_q_wd.io.enq.bits)} (${in_q_wd.io.enq.bits})") }
  when (out_q_rd.io.enq.fire) { info(p"enq read data: 0x${Hexadecimal(out_q_rd.io.enq.bits.data)} (${out_q_rd.io.enq.bits.data})") }
  when (out_q_rd.io.deq.fire) { info(p"deq read data: 0x${Hexadecimal(out_q_rd.io.deq.bits.data)} (${out_q_rd.io.deq.bits.data})") }
  when (out_q_wr.io.enq.fire) { info(p"enq write resp: 0x${Hexadecimal(out_q_wr.io.enq.bits)} (${out_q_wr.io.enq.bits})") }
  when (out_q_wr.io.deq.fire) { info(p"deq write resp: 0x${Hexadecimal(out_q_wr.io.deq.bits)} (${out_q_wr.io.deq.bits})") }*/
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

  io.saxi.readData.bits.defaults
  io.saxi.readData.valid  := false.B
  io.saxi.writeResp.bits.defaults
  io.saxi.writeResp.valid := false.B

  in_q_ra.io.enq.bits     := io.saxi.readAddr.bits.addr
  in_q_ra.io.enq.valid    := io.saxi.readAddr.valid
  io.saxi.readAddr.ready  := in_q_ra.io.enq.ready
  in_q_wa.io.enq.bits     := io.saxi.writeAddr.bits.addr
  in_q_wa.io.enq.valid    := io.saxi.writeAddr.valid
  io.saxi.writeAddr.ready := in_q_wa.io.enq.ready
  in_q_wd.io.enq.bits     := io.saxi.writeData.bits.data
  in_q_wd.io.enq.valid    := io.saxi.writeData.valid
  io.saxi.writeData.ready := in_q_wd.io.enq.ready

122
  val out_q_rd_enq_valid = RegNext(false.B, init = false.B)
123
  out_q_rd.io.enq.bits    := read_reg
124
  out_q_rd.io.enq.valid   := out_q_rd_enq_valid
125
126
127
  out_q_rd.io.deq.ready   := io.saxi.readData.ready
  io.saxi.readData.bits.data := out_q_rd.io.deq.bits.data
  io.saxi.readData.bits.resp := out_q_rd.io.deq.bits.resp
128
  io.saxi.readData.valid     := out_q_rd.io.deq.valid
129

130
  val out_q_wr_enq_valid = RegNext(false.B, init = false.B)
131
  out_q_wr.io.enq.bits    := resp_reg
132
  out_q_wr.io.enq.valid   := out_q_wr_enq_valid
133
134
135
136
  out_q_wr.io.deq.ready   := io.saxi.writeResp.ready
  io.saxi.writeResp.valid := out_q_wr.io.deq.valid
  io.saxi.writeResp.bits.bresp := out_q_wr.io.deq.bits

137
138
139
  in_q_ra.io.deq.ready    := out_q_rd.io.enq.ready

  when (in_q_ra.io.deq.fire) {
140
    val addr = in_q_ra.io.deq.bits
141
    read_reg.resp := Response.slverr
142
143
    for (off <- cfg.regs.keys.toList.sorted) {
      when (addr === off.U) { cfg.regs(off).read() map { v =>
144
        info(p"reading from address 0x${Hexadecimal(addr)} ($addr) -> 0x${Hexadecimal(v)} ($v)")
145
146
147
        read_reg.data := v
        read_reg.resp := Response.okay
      }}
Jens Korinth's avatar
Jens Korinth committed
148
    }
149
    out_q_rd_enq_valid := true.B
150
  }
151

152
153
154
155
  in_q_wa.io.deq.ready := in_q_wd.io.deq.valid && out_q_wr.io.enq.ready
  in_q_wd.io.deq.ready := in_q_wa.io.deq.valid && out_q_wr.io.enq.ready

  when (in_q_wa.io.deq.fire) {
156
    val addr = in_q_wa.io.deq.bits
157
    val v = in_q_wd.io.deq.bits
158
    for (off <- cfg.regs.keys.toList.sorted) {
159
160
161
162
163
      when (addr === off.U) {
        val r = cfg.regs(off).write(v)
        info(p"writing to address 0x${Hexadecimal(addr)} ($addr) -> 0x${Hexadecimal(v)} ($v): 0x${Hexadecimal(r)} ($r)")
        resp_reg := r
      }
Jens Korinth's avatar
Jens Korinth committed
164
    }
165
    out_q_wr_enq_valid := true.B
Jens Korinth's avatar
Jens Korinth committed
166
  }
167
168
169
170
171
172
173
174

  when (reset.toBool) { // this is required for AXI compliance; apparently Queues start working while reset is high
    io.saxi.readAddr.ready  := false.B
    io.saxi.readData.valid  := false.B
    io.saxi.writeAddr.ready := false.B
    io.saxi.writeData.ready := false.B
    io.saxi.writeResp.valid := false.B
  }
Jens Korinth's avatar
Jens Korinth committed
175
}