aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/passes/memlib/MemConf.scala
blob: 8063c6278787323a939349dbbb991e09dcf7a890 (plain)
1
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// SPDX-License-Identifier: Apache-2.0

package firrtl.passes
package memlib

sealed abstract class MemPort(val name: String) { override def toString = name }

case object ReadPort extends MemPort("read")
case object WritePort extends MemPort("write")
case object MaskedWritePort extends MemPort("mwrite")
case object ReadWritePort extends MemPort("rw")
case object MaskedReadWritePort extends MemPort("mrw")

object MemPort {

  // This is the order that ports will render in MemConf.portsStr
  val ordered: Seq[MemPort] = Seq(
    MaskedReadWritePort,
    MaskedWritePort,
    ReadWritePort,
    WritePort,
    ReadPort
  )

  val all: Set[MemPort] = ordered.toSet
  // uses orderedPorts when sorting MemPorts
  implicit def ordering: Ordering[MemPort] = {
    val orderedPorts = ordered.zipWithIndex.toMap
    Ordering.by(e => orderedPorts(e))
  }

  def apply(s: String): Option[MemPort] = MemPort.all.find(_.name == s)

  def fromString(s: String): Map[MemPort, Int] = {
    s.split(",")
      .toSeq
      .map(MemPort.apply)
      .map(_ match {
        case Some(x) => x
        case _       => throw new Exception(s"Error parsing MemPort string : ${s}")
      })
      .groupBy(identity)
      .mapValues(_.size)
      .toMap
  }
}

case class MemConf(
  name:            String,
  depth:           BigInt,
  width:           Int,
  ports:           Map[MemPort, Int],
  maskGranularity: Option[Int]) {

  private def portsStr =
    ports.toSeq.sortBy(_._1).map { case (port, num) => Seq.fill(num)(port.name).mkString(",") }.mkString(",")
  private def maskGranStr = maskGranularity.map((p) => s"mask_gran $p").getOrElse("")

  // Assert that all of the entries in the port map are greater than zero to make it easier to compare two of these case classes
  // (otherwise an entry of XYZPort -> 0 would not be equivalent to another with no XYZPort despite being semantically the same)
  ports.foreach { case (k, v) => require(v > 0, "Cannot have negative or zero entry in the port map") }

  override def toString = s"name ${name} depth ${depth} width ${width} ports ${portsStr} ${maskGranStr} \n"
}

object MemConf {

  val regex = raw"\s*name\s+(\w+)\s+depth\s+(\d+)\s+width\s+(\d+)\s+ports\s+([^\s]+)\s+(?:mask_gran\s+(\d+))?\s*".r

  def fromString(s: String): Seq[MemConf] = {
    s.split("\n")
      .toSeq
      .map(_ match {
        case MemConf.regex(name, depth, width, ports, maskGran) =>
          Some(MemConf(name, BigInt(depth), width.toInt, MemPort.fromString(ports), Option(maskGran).map(_.toInt)))
        case "" => None
        case _  => throw new Exception(s"Error parsing MemConf string : ${s}")
      })
      .flatten
  }

  def apply(
    name:            String,
    depth:           BigInt,
    width:           Int,
    readPorts:       Int,
    writePorts:      Int,
    readWritePorts:  Int,
    maskGranularity: Option[Int]
  ): MemConf = {
    val ports: Seq[(MemPort, Int)] = (if (maskGranularity.isEmpty) {
                                        (if (writePorts == 0) Seq() else Seq(WritePort -> writePorts)) ++
                                          (if (readWritePorts == 0) Seq() else Seq(ReadWritePort -> readWritePorts))
                                      } else {
                                        (if (writePorts == 0) Seq() else Seq(MaskedWritePort -> writePorts)) ++
                                          (if (readWritePorts == 0) Seq()
                                           else Seq(MaskedReadWritePort -> readWritePorts))
                                      }) ++ (if (readPorts == 0) Seq() else Seq(ReadPort -> readPorts))
    new MemConf(name, depth, width, ports.toMap, maskGranularity)
  }
}