aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/passes/CheckChirrtl.scala
blob: a9a149821ea3932298a229aacbe2b12e9293e64d (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
// See LICENSE for license details.

package firrtl.passes

import firrtl._
import firrtl.ir._
import firrtl.Utils._
import firrtl.traversals.Foreachers._

object CheckChirrtl extends Pass {
  type NameSet = collection.mutable.HashSet[String]

  class NotUniqueException(info: Info, mname: String, name: String) extends PassException(
    s"$info: [module $mname] Reference $name does not have a unique name.")
  class InvalidLOCException(info: Info, mname: String) extends PassException(
    s"$info: [module $mname] Invalid connect to an expression that is not a reference or a WritePort.")
  class UndeclaredReferenceException(info: Info, mname: String, name: String) extends PassException(
    s"$info: [module $mname] Reference $name is not declared.")
  class MemWithFlipException(info: Info, mname: String, name: String) extends PassException(
    s"$info: [module $mname] Memory $name cannot be a bundle type with flips.")
  class InvalidAccessException(info: Info, mname: String) extends PassException(
    s"$info: [module $mname] Invalid access to non-reference.")
  class ModuleNotDefinedException(info: Info, mname: String, name: String) extends PassException(
    s"$info: Module $name is not defined.")
  class NegWidthException(info: Info, mname: String) extends PassException(
    s"$info: [module $mname] Width cannot be negative or zero.")
  class NegVecSizeException(info: Info, mname: String) extends PassException(
    s"$info: [module $mname] Vector type size cannot be negative.")
  class NegMemSizeException(info: Info, mname: String) extends PassException(
    s"$info: [module $mname] Memory size cannot be negative or zero.")
  class NoTopModuleException(info: Info, name: String) extends PassException(
    s"$info: A single module must be named $name.")

  def run (c: Circuit): Circuit = {
    val errors = new Errors()
    val moduleNames = (c.modules map (_.name)).toSet

    def checkValidLoc(info: Info, mname: String, e: Expression) = e match {
      case _: UIntLiteral | _: SIntLiteral | _: DoPrim =>
        errors append new InvalidLOCException(info, mname)
      case _ => // Do Nothing
    }
    def checkChirrtlW(info: Info, mname: String)(w: Width): Unit = w match {
      case w: IntWidth if (w.width < BigInt(0)) => errors.append(new NegWidthException(info, mname))
      case _ =>
    }

    def checkChirrtlT(info: Info, mname: String)(t: Type): Unit = {
      t.foreach(checkChirrtlT(info, mname))
      t match {
        case t: VectorType if t.size < 0 =>
          errors append new NegVecSizeException(info, mname)
          t.foreach(checkChirrtlW(info, mname))
        //case FixedType(width, point) => FixedType(checkChirrtlW(width), point)
        case _ => t.foreach(checkChirrtlW(info, mname))
      }
    }

    def validSubexp(info: Info, mname: String)(e: Expression): Unit = e match {
      case _: Reference | _: SubField | _: SubIndex | _: SubAccess |
           _: Mux | _: ValidIf => // No error
      case _ => errors append new InvalidAccessException(info, mname)
    }

    def checkChirrtlE(info: Info, mname: String, names: NameSet)(e: Expression): Unit = {
      e match {
        case _: DoPrim | _:Mux | _:ValidIf | _: UIntLiteral =>
        case ex: Reference if !names(ex.name) =>
          errors append new UndeclaredReferenceException(info, mname, ex.name)
        case ex: SubAccess => validSubexp(info, mname)(ex.expr)
        case ex => ex.foreach(validSubexp(info, mname))
      }
      e.foreach(checkChirrtlW(info, mname))
      e.foreach(checkChirrtlT(info, mname))
      e.foreach(checkChirrtlE(info, mname, names))
    }

    def checkName(info: Info, mname: String, names: NameSet)(name: String): Unit = {
      if (names(name))
        errors append new NotUniqueException(info, mname, name)
      names += name
    }

    def checkChirrtlS(minfo: Info, mname: String, names: NameSet)(s: Statement): Unit = {
      val info = get_info(s) match {case NoInfo => minfo case x => x}
      s.foreach(checkName(info, mname, names))
      s match {
        case sx: DefMemory =>
          if (hasFlip(sx.dataType)) errors append new MemWithFlipException(info, mname, sx.name)
          if (sx.depth <= 0) errors append new NegMemSizeException(info, mname)
        case sx: DefInstance if !moduleNames(sx.module) =>
          errors append new ModuleNotDefinedException(info, mname, sx.module)
        case sx: Connect => checkValidLoc(info, mname, sx.loc)
        case sx: PartialConnect => checkValidLoc(info, mname, sx.loc)
        case _ => // Do Nothing
      }
      s.foreach(checkChirrtlT(info, mname))
      s.foreach(checkChirrtlE(info, mname, names))
      s.foreach(checkChirrtlS(info, mname, names))
    }

    def checkChirrtlP(mname: String, names: NameSet)(p: Port): Unit = {
      if (names(p.name))
        errors append new NotUniqueException(NoInfo, mname, p.name)
      names += p.name
      p.tpe.foreach(checkChirrtlT(p.info, mname))
      p.tpe.foreach(checkChirrtlW(p.info, mname))
    }

    def checkChirrtlM(m: DefModule) {
      val names = new NameSet
      m.foreach(checkChirrtlP(m.name, names))
      m.foreach(checkChirrtlS(m.info, m.name, names))
    }
    
    c.modules.foreach(checkChirrtlM)
    c.modules count (_.name == c.main) match {
      case 1 =>
      case _ => errors append new NoTopModuleException(c.info, c.main)
    }
    errors.trigger()
    c
  }
}