aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/passes/ReplSeqMem.scala
blob: ae842a0b33506d35ca5b756b027ddad478a61b36 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// See LICENSE for license details.

package firrtl.passes

import com.typesafe.scalalogging.LazyLogging
import firrtl._
import firrtl.ir._
import Annotations._
import java.io.Writer
import AnalysisUtils._

sealed trait PassOption
case object InputConfigFileName extends PassOption
case object OutputConfigFileName extends PassOption
case object PassCircuitName extends PassOption

object PassConfigUtil {

  def getPassOptions(t: String, usage: String = "") = {
    
    type PassOptionMap = Map[PassOption, String] 

    // can't use space to delimit sub arguments (otherwise, Driver.scala will throw error)
    val passArgList = t.split(":").toList
    
    def nextPassOption(map: PassOptionMap, list: List[String]): PassOptionMap = {
      list match {
        case Nil => map
        case "-i" :: value :: tail =>
          nextPassOption(map + (InputConfigFileName -> value), tail)
        case "-o" :: value :: tail =>
          nextPassOption(map + (OutputConfigFileName -> value), tail)
        case "-c" :: value :: tail =>
          nextPassOption(map + (PassCircuitName -> value), tail)
        case option :: tail =>
          error("Unknown option " + option + usage)
      }
    }
    nextPassOption(Map[PassOption, String](), passArgList)
  }

}

class ConfWriter(filename: String) {
  val outputBuffer = new java.io.CharArrayWriter
  def append(m: DefMemory) = {
    // legacy
    val maskGran = getInfo(m.info, "maskGran")
    val writers = m.writers map (x => if (maskGran == None) "write" else "mwrite")
    val readers = List.fill(m.readers.length)("read")
    val readwriters = m.readwriters map (x => if (maskGran == None) "rw" else "mrw")
    val ports = (writers ++ readers ++ readwriters).mkString(",")
    val maskGranConf = if (maskGran == None) "" else s"mask_gran ${maskGran.get}"
    val width = bitWidth(m.dataType)
    val conf = s"name ${m.name} depth ${m.depth} width ${width} ports ${ports} ${maskGranConf} \n"
    outputBuffer.append(conf)
  }
  def serialize = {
    val outputFile = new java.io.PrintWriter(filename)
    outputFile.write(outputBuffer.toString)
    outputFile.close()
  }
}

case class ReplSeqMemAnnotation(t: String, tID: TransID)
    extends Annotation with Loose with Unstable {

  val usage = """
[Optional] ReplSeqMem
  Pass to replace sequential memories with blackboxes + configuration file

Usage: 
  --replSeqMem -c:<circuit>:-i:<filename>:-o:<filename>
  *** Note: sub-arguments to --replSeqMem should be delimited by : and not white space!

Required Arguments:
  -o<filename>         Specify the output configuration file
  -c<compiler>         Specify the target circuit

Optional Arguments:
  -i<filename>         Specify the input configuration file (for additional optimizations)
"""    

  val passOptions = PassConfigUtil.getPassOptions(t, usage)
  val outputConfig = passOptions.getOrElse(
    OutputConfigFileName, 
    error("No output config file provided for ReplSeqMem!" + usage)
  )
  val passCircuit = passOptions.getOrElse(
    PassCircuitName, 
    error("No circuit name specified for ReplSeqMem!" + usage)
  )
  val target = CircuitName(passCircuit)
  def duplicate(n: Named) = this.copy(t=t.replace("-c:"+passCircuit, "-c:"+n.name))
  
}

class ReplSeqMem(transID: TransID) extends Transform with LazyLogging {
  def execute(circuit:Circuit, map: AnnotationMap) = 
    map get transID match {
      case Some(p) => p get CircuitName(circuit.main) match {
        case Some(ReplSeqMemAnnotation(t, _)) => {

          val inputFileName = PassConfigUtil.getPassOptions(t).getOrElse(InputConfigFileName, "")
          val inConfigFile = {
            if (inputFileName.isEmpty) None 
            else if (new java.io.File(inputFileName).exists) Some(new YamlFileReader(inputFileName))
            else error("Input configuration file does not exist!")
          }

          val outConfigFile = new ConfWriter(PassConfigUtil.getPassOptions(t).get(OutputConfigFileName).get)
          TransformResult(
            (
              Seq(
                Legalize,
                AnnotateMemMacros,
                UpdateDuplicateMemMacros,
                new AnnotateValidMemConfigs(inConfigFile),
                new ReplaceMemMacros(outConfigFile),
                RemoveEmpty,
                CheckInitialization,
                ResolveKinds,                                       // Must be run for the transform to work!
                InferTypes,
                ResolveGenders
              ) foldLeft circuit
            ) { 
              (c, pass) =>
                val x = Utils.time(pass.name)(pass run c)
                logger debug x.serialize
                x
            } , 
            None, 
            Some(map)
          )
        }  
        case _ => error("Unexpected transform annotation")
      }
      case _ => TransformResult(circuit, None, Some(map))
    }
}