aboutsummaryrefslogtreecommitdiff
path: root/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
blob: 85f346066b4972df401e14b4705a17bc863505a0 (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
// See LICENSE for license details.

package firrtlTests.fixed

import java.io.StringWriter

import firrtl.Annotations.AnnotationMap
import firrtl.{LowFirrtlCompiler, Parser}
import firrtl.Parser.IgnoreInfo
import firrtlTests.FirrtlFlatSpec

class FixedPointMathSpec extends FirrtlFlatSpec {
  def parse (input:String) = Parser.parse(input.split("\n").toIterator, IgnoreInfo)

  "Fixed types" should "parse" in {
    val SumPattern        = """.*output sum.*<(\d+)>.*.*""".r
    val ProductPattern    = """.*output product.*<(\d+)>.*""".r
    val DifferencePattern = """.*output difference.*<(\d+)>.*""".r

    val AssignPattern     = """\s*(\w+) <= (\w+)\((.*)\)\s*""".r

    for {
      bits1        <- 1 to 4
//      binaryPoint1 <- -4 to 4
      binaryPoint1 <- 1 to 4
      bits2        <- 1 to 4
//      binaryPoint2 <- -4 to 4
      binaryPoint2 <- 1 to 4
    } {
      val input =
        s"""circuit Unit :
        |  module Unit :
        |    input  a : Fixed<$bits1><<$binaryPoint1>>
        |    input  b : Fixed<$bits2><<$binaryPoint2>>
        |    output sum        : Fixed
        |    output product    : Fixed
        |    output difference : Fixed
        |    sum        <= add(a, b)
        |    product    <= mul(a, b)
        |    difference <= sub(a, b)
        |    """.
          stripMargin

      val lowerer = new LowFirrtlCompiler

      val writer = new StringWriter()

      lowerer.compile(parse(input), new AnnotationMap(Seq.empty), writer)

      val output = writer.toString.split("\n")

      def config = s"($bits1,$binaryPoint1)($bits2,$binaryPoint2)"

      def inferredAddWidth: Int = {
        val binaryDifference = binaryPoint1 - binaryPoint2
        val (newW1, newW2) = if(binaryDifference > 0) {
          (bits1, bits2 + binaryDifference)
        } else {
          (bits1 + binaryDifference.abs, bits2)
        }
        newW1.max(newW2) + 1
      }

      println(s"Test for configuratio $config")

      for(line <- output) {
        line  match {
          case SumPattern(varWidth)     =>
            assert(varWidth.toInt === inferredAddWidth, s"$config sum sint bits wrong for $line")
          case ProductPattern(varWidth) =>
            assert(varWidth.toInt === bits1 + bits2, s"$config product bits wrong for $line")
          case DifferencePattern(varWidth)     =>
            assert(varWidth.toInt === inferredAddWidth, s"$config difference bits wrong for $line")
          case AssignPattern(varName, operation, args) =>
            varName match {
              case "sum" =>
                assert(operation === "add", s"var sum should be result of an add in $line")
                if (binaryPoint1 > binaryPoint2) {
                  assert(!args.contains("shl(a"), s"$config first arg should be just a in $line")
                  assert(args.contains(s"shl(b, ${binaryPoint1 - binaryPoint2})"),
                    s"$config second arg incorrect in $line")
                } else if (binaryPoint1 < binaryPoint2) {
                  assert(args.contains(s"shl(a, ${(binaryPoint1 - binaryPoint2).abs})"),
                    s"$config second arg incorrect in $line")
                  assert(!args.contains("shl(b"), s"$config second arg should be just b in $line")
                } else {
                  assert(!args.contains("shl(a"), s"$config first arg should be just a in $line")
                  assert(!args.contains("shl(b"), s"$config second arg should be just b in $line")
                }
              case "product" =>
                assert(operation === "mul", s"var sum should be result of an add in $line")
                assert(!args.contains("shl(a"), s"$config first arg should be just a in $line")
                assert(!args.contains("shl(b"), s"$config second arg should be just b in $line")
              case "difference" =>
                assert(operation === "sub", s"var difference should be result of an sub in $line")
                if (binaryPoint1 > binaryPoint2) {
                  assert(!args.contains("shl(a"), s"$config first arg should be just a in $line")
                  assert(args.contains(s"shl(b, ${binaryPoint1 - binaryPoint2})"),
                    s"$config second arg incorrect in $line")
                } else if (binaryPoint1 < binaryPoint2) {
                  assert(args.contains(s"shl(a, ${(binaryPoint1 - binaryPoint2).abs})"),
                    s"$config second arg incorrect in $line")
                  assert(!args.contains("shl(b"), s"$config second arg should be just b in $line")
                } else {
                  assert(!args.contains("shl(a"), s"$config first arg should be just a in $line")
                  assert(!args.contains("shl(b"), s"$config second arg should be just b in $line")
                }
              case _ =>
            }
          case _ =>
//            println(s"No pattern found for ${line}")
        }
      }

      println(writer.toString)
    }
  }
}