Files
chipyard/tapeout/src/test/scala/mdf/macrolib/MacroLibSpec.scala
chick c907a7377c Moved a zillion files all over the place so that everything is now
in tapeout/src in the correct directory corresponding to internal packages.
Everything compiles and tests run
TODO:
- Figure out assembly step for MacroCompiler
- Does root project matter?
2021-08-06 13:09:45 -07:00

407 lines
11 KiB
Scala

package mdf.macrolib
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import play.api.libs.json._
object JSONUtils {
def readStringValueMap(str: String): Option[Map[String, JsValue]] = {
Json.parse(str) match {
case x: JsObject => Some(x.as[Map[String, JsValue]])
case _ => None
}
}
}
// Tests for filler macros
class FillerMacroSpec extends AnyFlatSpec with Matchers {
"Valid lvt macros" should "be detected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "filler cell",
| "name": "MY_FILLER_CELL",
| "vt": "lvt"
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe Some(FillerMacro("MY_FILLER_CELL", "lvt"))
}
"Valid metal macro" should "be detected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "metal filler cell",
| "name": "METAL_FILLER_CELL",
| "vt": "lvt"
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe Some(MetalFillerMacro("METAL_FILLER_CELL", "lvt"))
}
"Valid hvt macros" should "be detected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "filler cell",
| "name": "HVT_CELL_PROP",
| "vt": "hvt"
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe Some(FillerMacro("HVT_CELL_PROP", "hvt"))
}
"Empty name macros" should "be rejected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "filler cell",
| "name": "",
| "vt": "hvt"
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe None
}
"Empty vt macros" should "be rejected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "metal filler cell",
| "name": "DEAD_CELL",
| "vt": ""
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe None
}
"Missing vt macros" should "be rejected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "metal filler cell",
| "name": "DEAD_CELL"
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe None
}
"Missing name macros" should "be rejected" in {
val m = JSONUtils
.readStringValueMap("""
| {
| "type": "filler cell",
| "vt": ""
| }
|""".stripMargin)
.get
FillerMacroBase.parseJSON(m) shouldBe None
}
}
// Tests for SRAM type and associates.
class SRAMMacroSpec extends AnyFlatSpec with Matchers {
// Simple port which can be reused in tests
// Note: assume width=depth=simplePortConstant.
val simplePortConstant = 1024
def simplePort(
postfix: String = "",
width: Int = simplePortConstant,
depth: Int = simplePortConstant
): (String, MacroPort) = {
val json = s"""
{
"address port name": "A_${postfix}",
"address port polarity": "active high",
"clock port name": "CLK_${postfix}",
"clock port polarity": "positive edge",
"write enable port name": "WEN_${postfix}",
"write enable port polarity": "active high",
"read enable port name": "REN_${postfix}",
"read enable port polarity": "active high",
"chip enable port name": "CEN_${postfix}",
"chip enable port polarity": "active high",
"output port name": "OUT_${postfix}",
"output port polarity": "active high",
"input port name": "IN_${postfix}",
"input port polarity": "active high",
"mask granularity": 1,
"mask port name": "MASK_${postfix}",
"mask port polarity": "active high"
}
"""
val port = MacroPort(
address = PolarizedPort(s"A_${postfix}", ActiveHigh),
clock = Some(PolarizedPort(s"CLK_${postfix}", PositiveEdge)),
writeEnable = Some(PolarizedPort(s"WEN_${postfix}", ActiveHigh)),
readEnable = Some(PolarizedPort(s"REN_${postfix}", ActiveHigh)),
chipEnable = Some(PolarizedPort(s"CEN_${postfix}", ActiveHigh)),
output = Some(PolarizedPort(s"OUT_${postfix}", ActiveHigh)),
input = Some(PolarizedPort(s"IN_${postfix}", ActiveHigh)),
maskPort = Some(PolarizedPort(s"MASK_${postfix}", ActiveHigh)),
maskGran = Some(1),
width = Some(width),
depth = Some(depth)
)
(json, port)
}
"Simple port" should "be valid" in {
{
val (json, port) = simplePort("Simple1")
MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some(
port
)
}
{
val (json, port) = simplePort("Simple2")
MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some(
port
)
}
{
val (json, port) = simplePort("bar")
MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some(
port
)
}
{
val (json, port) = simplePort("")
MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some(
port
)
}
}
"Simple SRAM macro" should "be detected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 2048,
"depth": "4096",
"family": "1rw",
"ports": [
${json}
]
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe Some(
SRAMMacro("SRAMS_R_US", width = 2048, depth = 4096, family = "1rw", ports = List(port), extraPorts = List())
)
}
"Non-power-of-two width & depth SRAM macro" should "be detected" in {
val (json, port) = simplePort("", 1234, 8888)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 1234,
"depth": "8888",
"family": "1rw",
"ports": [
${json}
]
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe Some(
SRAMMacro("SRAMS_R_US", width = 1234, depth = 8888, family = "1rw", ports = List(port), extraPorts = List())
)
}
"Minimal memory port" should "be detected" in {
val (json, port) = simplePort("_A", 64, 1024)
val port2 = MacroPort(
address = PolarizedPort("A_B", ActiveHigh),
clock = Some(PolarizedPort("CLK_B", PositiveEdge)),
writeEnable = Some(PolarizedPort("WEN_B", ActiveHigh)),
readEnable = None,
chipEnable = None,
output = Some(PolarizedPort("OUT_B", ActiveHigh)),
input = Some(PolarizedPort("IN_B", ActiveHigh)),
maskPort = None,
maskGran = None,
width = Some(64),
depth = Some(1024)
)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 64,
"depth": "1024",
"family": "2rw",
"ports": [
${json},
{
"address port name": "A_B",
"address port polarity": "active high",
"clock port name": "CLK_B",
"clock port polarity": "positive edge",
"write enable port name": "WEN_B",
"write enable port polarity": "active high",
"output port name": "OUT_B",
"output port polarity": "active high",
"input port name": "IN_B",
"input port polarity": "active high"
}
]
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe Some(
SRAMMacro("SRAMS_R_US", width = 64, depth = 1024, family = "2rw", ports = List(port, port2), extraPorts = List())
)
}
"Extra ports" should "be detected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "GOT_EXTRA",
"width": 2048,
"depth": "4096",
"family": "1rw",
"ports": [
${json}
],
"extra ports": [
{
"name": "TIE_DIE",
"width": 1,
"type": "constant",
"value": 1
},
{
"name": "TIE_MOO",
"width": 4,
"type": "constant",
"value": 0
}
]
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe Some(
SRAMMacro(
"GOT_EXTRA",
width = 2048,
depth = 4096,
family = "1rw",
ports = List(port),
extraPorts = List(
MacroExtraPort(
name = "TIE_DIE",
width = 1,
portType = Constant,
value = 1
),
MacroExtraPort(
name = "TIE_MOO",
width = 4,
portType = Constant,
value = 0
)
)
)
)
}
"Invalid port" should "be rejected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 2048,
"depth": "4096",
"family": "1rw",
"ports": [
{
"address port name": "missing_polarity",
"output port name": "missing_clock"
}
]
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe None
}
"No ports" should "be rejected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 2048,
"depth": "4096",
"family": "1rw"
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe None
}
"No family and ports" should "be rejected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "SRAMS_R_US",
"width": 2048,
"depth": "4096"
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe None
}
"String width" should "be rejected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "BAD_BAD_SRAM",
"width": "wide",
"depth": "4096"
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe None
}
"String depth" should "be rejected" in {
val (json, port) = simplePort("", 2048, 4096)
val m = JSONUtils
.readStringValueMap(s"""
{
"type": "sram",
"name": "BAD_BAD_SRAM",
"width": 512,
"depth": "octopus_under_the_sea"
}
""")
.get
SRAMMacro.parseJSON(m) shouldBe None
}
}