// See LICENSE for license details. package firrtl.passes import firrtl._ import firrtl.ir._ import firrtl.Utils._ import firrtl.Mappers._ 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.") // TODO FIXME // - Do we need to check for uniquness on port names? 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): Width = w match { case w: IntWidth if (w.width < BigInt(0)) => errors.append(new NegWidthException(info, mname)) w case _ => w } def checkChirrtlT(info: Info, mname: String)(t: Type): Type = t map checkChirrtlT(info, mname) match { case t: VectorType if t.size < 0 => errors append new NegVecSizeException(info, mname) t map checkChirrtlW(info, mname) //case FixedType(width, point) => FixedType(checkChirrtlW(width), point) case _ => t map checkChirrtlW(info, mname) } def validSubexp(info: Info, mname: String)(e: Expression): Expression = { e match { case _: Reference | _: SubField | _: SubIndex | _: SubAccess | _: Mux | _: ValidIf => // No error case _ => errors append new InvalidAccessException(info, mname) } e } def checkChirrtlE(info: Info, mname: String, names: NameSet)(e: Expression): Expression = { 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 map validSubexp(info, mname) } (e map checkChirrtlW(info, mname) map checkChirrtlT(info, mname) map checkChirrtlE(info, mname, names)) } def checkName(info: Info, mname: String, names: NameSet)(name: String): String = { if (names(name)) errors append new NotUniqueException(info, mname, name) names += name name } def checkChirrtlS(minfo: Info, mname: String, names: NameSet)(s: Statement): Statement = { val info = get_info(s) match {case NoInfo => minfo case x => x} s map checkName(info, mname, names) 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 map checkChirrtlT(info, mname) map checkChirrtlE(info, mname, names) map checkChirrtlS(info, mname, names)) } def checkChirrtlP(mname: String, names: NameSet)(p: Port): Port = { names += p.name (p.tpe map checkChirrtlT(p.info, mname) map checkChirrtlW(p.info, mname)) p } def checkChirrtlM(m: DefModule) { val names = new NameSet (m map checkChirrtlP(m.name, names) map 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 } }