96 lines
3.7 KiB
Scala
96 lines
3.7 KiB
Scala
package mdf.macrolib
|
|
|
|
object ConfReader {
|
|
import scala.util.matching.Regex._
|
|
|
|
type ConfPort = (String, Boolean) // prefix (e.g. "RW0") and true if masked
|
|
|
|
/** Rename ports like "read" to R0, "write" to W0, and "rw" to RW0, and
|
|
* return a count of read, write, and readwrite ports.
|
|
*/
|
|
def renamePorts(ports: Seq[String]): (Seq[ConfPort], Int, Int, Int) = {
|
|
var readCount = 0
|
|
var writeCount = 0
|
|
var readWriteCount = 0
|
|
(
|
|
ports.map {
|
|
_ match {
|
|
case "read" => readCount += 1; (s"R${readCount - 1}", false)
|
|
case "write" => writeCount += 1; (s"W${writeCount - 1}", false)
|
|
case "mwrite" => writeCount += 1; (s"W${writeCount - 1}", true)
|
|
case "rw" => readWriteCount += 1; (s"RW${readWriteCount - 1}", false)
|
|
case "mrw" => readWriteCount += 1; (s"RW${readWriteCount - 1}", true)
|
|
}
|
|
},
|
|
readCount,
|
|
writeCount,
|
|
readWriteCount
|
|
)
|
|
}
|
|
|
|
def generateFirrtlPort(port: ConfPort, width: Int, depth: Int, maskGran: Option[Int]): MacroPort = {
|
|
val (prefix, masked) = port
|
|
val isReadWriter = prefix.startsWith("RW")
|
|
val isReader = prefix.startsWith("R") && !isReadWriter
|
|
val isWriter = prefix.startsWith("W")
|
|
val r = if (isReadWriter) "r" else ""
|
|
val w = if (isReadWriter) "w" else ""
|
|
MacroPort(
|
|
address = PolarizedPort(s"${prefix}_addr", ActiveHigh),
|
|
clock = Some(PolarizedPort(s"${prefix}_clk", PositiveEdge)),
|
|
writeEnable = if (isReadWriter) Some(PolarizedPort(s"${prefix}_${w}mode", ActiveHigh)) else None,
|
|
output = if (isReader || isReadWriter) Some(PolarizedPort(s"${prefix}_${w}data", ActiveHigh)) else None,
|
|
input = if (isWriter || isReadWriter) Some(PolarizedPort(s"${prefix}_${r}data", ActiveHigh)) else None,
|
|
maskPort = if (masked) Some(PolarizedPort(s"${prefix}_${w}mask", ActiveHigh)) else None,
|
|
maskGran = if (masked) maskGran else None,
|
|
width = Some(width),
|
|
depth = Some(depth)
|
|
)
|
|
}
|
|
|
|
/** Read a conf line into a SRAMMacro, but returns an error string in Left
|
|
* instead of throwing errors if the line is malformed.
|
|
*/
|
|
def readSingleLineSafe(line: String): Either[String, SRAMMacro] = {
|
|
val pattern = """name ([^\s]+) depth (\d+) width (\d+) ports ([a-z,]+)\s?(?:mask_gran (\d+))?""".r
|
|
pattern.findFirstMatchIn(line) match {
|
|
case Some(m: Match) => {
|
|
val name: String = m.group(1)
|
|
val depth: Int = (m.group(2)).toInt
|
|
val width: Int = (m.group(3)).toInt
|
|
val ports: Seq[String] = (m.group(4)).split(",")
|
|
val (firrtlPorts, readPortCount, writePortCount, readWritePortCount) = renamePorts(ports)
|
|
val familyStr =
|
|
(if (readPortCount > 0) s"${readPortCount}r" else "") +
|
|
(if (writePortCount > 0) s"${writePortCount}w" else "") +
|
|
(if (readWritePortCount > 0) s"${readWritePortCount}rw" else "")
|
|
val maskGran: Option[Int] = Option(m.group(5)).map(_.toInt)
|
|
Right(
|
|
SRAMMacro(
|
|
name = name,
|
|
width = width,
|
|
depth = depth,
|
|
family = familyStr,
|
|
vt = "",
|
|
mux = 1,
|
|
ports = firrtlPorts.map(generateFirrtlPort(_, width, depth, maskGran)),
|
|
extraPorts = List()
|
|
)
|
|
)
|
|
}
|
|
case _ => Left("Input line did not match conf regex")
|
|
}
|
|
}
|
|
|
|
/** Read a conf line into a SRAMMacro. */
|
|
def readSingleLine(line: String): SRAMMacro = {
|
|
readSingleLineSafe(line).right.get
|
|
}
|
|
|
|
/** Read the contents of the conf file into a seq of SRAMMacro. */
|
|
def readFromString(contents: String): Seq[SRAMMacro] = {
|
|
// Trim, remove empty lines, then pass to readSingleLine
|
|
contents.split("\n").map(_.trim).filter(_ != "").map(readSingleLine(_))
|
|
}
|
|
}
|