From 44e079a0510f14abf6191b08f3082bd194d9fa60 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Wed, 27 Apr 2016 00:28:06 -0700 Subject: Fix LowerTypes to check for wmode instead of rmode --- src/main/scala/firrtl/passes/LowerTypes.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/LowerTypes.scala b/src/main/scala/firrtl/passes/LowerTypes.scala index 2caa2ce2..1dc3f782 100644 --- a/src/main/scala/firrtl/passes/LowerTypes.scala +++ b/src/main/scala/firrtl/passes/LowerTypes.scala @@ -100,7 +100,7 @@ object LowerTypes extends Pass { def lowerTypesMemExp(e: Expression): Seq[Expression] = { val (mem, port, field, tail) = splitMemRef(e) // Fields that need to be replicated for each resulting mem - if (Seq("addr", "en", "clk", "rmode").contains(field.name)) { + if (Seq("addr", "en", "clk", "wmode").contains(field.name)) { require(tail.isEmpty) // there can't be a tail for these val memType = memDataTypeMap(mem.name) -- cgit v1.2.3 From b9bf7ad196a203526977c0e299b60948be6b29c6 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Wed, 27 Apr 2016 00:29:05 -0700 Subject: Remove nested AND in creation of readwrite ports for mems. Fixes #147 --- src/main/scala/firrtl/Emitter.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 5414053a..17cb9d50 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -554,7 +554,13 @@ class VerilogEmitter extends Emitter { val rmem_port = WSubAccess(mem,raddrx,s.data_type,UNKNOWNGENDER) assign(rdata,rmem_port) val wmem_port = WSubAccess(mem,waddrx,s.data_type,UNKNOWNGENDER) - update(wmem_port,datax,clk,AND(AND(enx,maskx),wmode)) + + val tempName = namespace.newTemp + val tempExp = AND(enx,maskx) + declare("wire", tempName, tpe(tempExp)) + val tempWRef = wref(tempName, tpe(tempExp)) + assign(tempWRef, tempExp) + update(wmem_port,datax,clk,AND(tempWRef,wmode)) } } case (s:Begin) => s map (build_streams) -- cgit v1.2.3 From 89cbd83265c5bfb3968865ebaddf79efb4f47050 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Wed, 27 Apr 2016 00:32:38 -0700 Subject: Add integration test for single-ported memory --- src/test/scala/firrtlTests/IntegrationSpec.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/scala/firrtlTests/IntegrationSpec.scala b/src/test/scala/firrtlTests/IntegrationSpec.scala index 13e289d5..df4104a8 100644 --- a/src/test/scala/firrtlTests/IntegrationSpec.scala +++ b/src/test/scala/firrtlTests/IntegrationSpec.scala @@ -35,7 +35,8 @@ class IntegrationSpec extends FirrtlPropSpec { case class Test(name: String, dir: String) val runTests = Seq(Test("GCDTester", "/integration"), - Test("RightShiftTester", "/integration")) + Test("RightShiftTester", "/integration"), + Test("MemTester", "/integration")) runTests foreach { test => -- cgit v1.2.3 From 243ff24f8eb9aae18bb0c7afe4f4c1e6cd66c084 Mon Sep 17 00:00:00 2001 From: Colin Schmidt Date: Tue, 19 Apr 2016 09:51:24 -0700 Subject: add better type mismatch error message also check for it int unittest --- src/main/scala/firrtl/passes/Checks.scala | 6 +++--- src/test/scala/firrtlTests/UnitTests.scala | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala index 618c0e99..b68b7431 100644 --- a/src/main/scala/firrtl/passes/Checks.scala +++ b/src/main/scala/firrtl/passes/Checks.scala @@ -306,7 +306,7 @@ object CheckTypes extends Pass with LazyLogging { class AccessIndexNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Access index must be a UInt type.") class IndexNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Index is not of UIntType.") class EnableNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Enable is not of UIntType.") - class InvalidConnect(info:Info) extends PassException(s"${info}: [module ${mname}] Type mismatch.") + class InvalidConnect(info:Info, lhs:String, rhs:String) extends PassException(s"${info}: [module ${mname}] Type mismatch. Cannot connect ${lhs} to ${rhs}.") class InvalidRegInit(info:Info) extends PassException(s"${info}: [module ${mname}] Type of init must match type of DefRegister.") class PrintfArgNotGround(info:Info) extends PassException(s"${info}: [module ${mname}] Printf arguments must be either UIntType or SIntType.") class ReqClk(info:Info) extends PassException(s"${info}: [module ${mname}] Requires a clock typed signal.") @@ -479,9 +479,9 @@ object CheckTypes extends Pass with LazyLogging { def check_types_s (s:Stmt) : Stmt = { s map (check_types_e(get_info(s))) match { - case (s:Connect) => if (wt(tpe(s.loc)) != wt(tpe(s.exp))) errors += new InvalidConnect(s.info) + case (s:Connect) => if (wt(tpe(s.loc)) != wt(tpe(s.exp))) errors += new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize) case (s:DefRegister) => if (wt(s.tpe) != wt(tpe(s.init))) errors += new InvalidRegInit(s.info) - case (s:BulkConnect) => if (!bulk_equals(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT) ) errors += new InvalidConnect(s.info) + case (s:BulkConnect) => if (!bulk_equals(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT) ) errors += new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize) case (s:Stop) => { if (wt(tpe(s.clk)) != wt(ClockType()) ) errors += new ReqClk(s.info) if (wt(tpe(s.en)) != wt(ut()) ) errors += new EnNotUInt(s.info) diff --git a/src/test/scala/firrtlTests/UnitTests.scala b/src/test/scala/firrtlTests/UnitTests.scala index cee2c15d..dac8a40f 100644 --- a/src/test/scala/firrtlTests/UnitTests.scala +++ b/src/test/scala/firrtlTests/UnitTests.scala @@ -60,11 +60,12 @@ class UnitTests extends FirrtlFlatSpec { | input y: {a : UInt<1>} | output x: {a : UInt<1>, b : UInt<1>} | x <= y""".stripMargin - intercept[PassExceptions] { + val thrown = intercept[PassExceptions] { passes.foldLeft(parse(input)) { (c: Circuit, p: Pass) => p.run(c) } } + assert(thrown.getMessage contains "Type mismatch. Cannot connect") } "Initializing a register with a different type" should "throw an exception" in { -- cgit v1.2.3 From f9e8895b73aeec9bb71449f8e3d0e6f7e7a0a478 Mon Sep 17 00:00:00 2001 From: azidar Date: Tue, 24 May 2016 10:17:51 -0700 Subject: Added Errors class and fixed tests. Canonicalizes catching/throwing PassExceptions. --- src/main/scala/firrtl/passes/Checks.scala | 86 +++++++++++++++--------------- src/main/scala/firrtl/passes/Passes.scala | 11 ++++ src/test/scala/firrtlTests/CheckSpec.scala | 2 +- src/test/scala/firrtlTests/UnitTests.scala | 5 +- 4 files changed, 57 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala index b68b7431..083a18fd 100644 --- a/src/main/scala/firrtl/passes/Checks.scala +++ b/src/main/scala/firrtl/passes/Checks.scala @@ -116,7 +116,7 @@ object CheckHighForm extends Pass with LazyLogging { private var mname: String = "" private var sinfo: Info = NoInfo def run (c:Circuit): Circuit = { - val errors = ArrayBuffer[PassException]() + val errors = new Errors() def checkHighFormPrimop(e: DoPrim) = { def correctNum(ne: Option[Int], nc: Int) = { ne match { @@ -289,7 +289,7 @@ object CheckHighForm extends Pass with LazyLogging { } sinfo = c.info if (numTopM != 1) errors.append(new NoTopModuleException(c.main)) - if (errors.nonEmpty) throw new PassExceptions(errors) + errors.trigger c } } @@ -326,32 +326,32 @@ object CheckTypes extends Pass with LazyLogging { def ut () : UIntType = UIntType(UnknownWidth()) def st () : SIntType = SIntType(UnknownWidth()) - def check_types_primop (e:DoPrim, errors:ArrayBuffer[PassException],info:Info) : Unit = { + def check_types_primop (e:DoPrim, errors:Errors, info:Info) : Unit = { def all_same_type (ls:Seq[Expression]) : Unit = { var error = false for (x <- ls) { if (wt(tpe(ls.head)) != wt(tpe(x))) error = true } - if (error) errors += new OpNotAllSameType(info,e.op.serialize) + if (error) errors.append(new OpNotAllSameType(info,e.op.serialize)) } def all_ground (ls:Seq[Expression]) : Unit = { var error = false for (x <- ls ) { if (!(tpe(x).typeof[UIntType] || tpe(x).typeof[SIntType])) error = true } - if (error) errors += new OpNotGround(info,e.op.serialize) + if (error) errors.append(new OpNotGround(info,e.op.serialize)) } def all_uint (ls:Seq[Expression]) : Unit = { var error = false for (x <- ls ) { if (!(tpe(x).typeof[UIntType])) error = true } - if (error) errors += new OpNotAllUInt(info,e.op.serialize) + if (error) errors.append(new OpNotAllUInt(info,e.op.serialize)) } def is_uint (x:Expression) : Unit = { var error = false if (!(tpe(x).typeof[UIntType])) error = true - if (error) errors += new OpNotUInt(info,e.op.serialize,x.serialize) + if (error) errors.append(new OpNotUInt(info,e.op.serialize,x.serialize)) } e.op match { @@ -391,7 +391,7 @@ object CheckTypes extends Pass with LazyLogging { } def run (c:Circuit) : Circuit = { - val errors = ArrayBuffer[PassException]() + val errors = new Errors() def passive (t:Type) : Boolean = { (t) match { case (_:UIntType|_:SIntType) => true @@ -414,39 +414,39 @@ object CheckTypes extends Pass with LazyLogging { (tpe(e.exp)) match { case (t:BundleType) => { val ft = t.fields.find(p => p.name == e.name) - if (ft == None) errors += new SubfieldNotInBundle(info,e.name) + if (ft == None) errors.append(new SubfieldNotInBundle(info,e.name)) } - case (t) => errors += new SubfieldOnNonBundle(info,e.name) + case (t) => errors.append(new SubfieldOnNonBundle(info,e.name)) } } case (e:WSubIndex) => { (tpe(e.exp)) match { case (t:VectorType) => { - if (e.value >= t.size) errors += new IndexTooLarge(info,e.value) + if (e.value >= t.size) errors.append(new IndexTooLarge(info,e.value)) } - case (t) => errors += new IndexOnNonVector(info) + case (t) => errors.append(new IndexOnNonVector(info)) } } case (e:WSubAccess) => { (tpe(e.exp)) match { case (t:VectorType) => false - case (t) => errors += new IndexOnNonVector(info) + case (t) => errors.append(new IndexOnNonVector(info)) } (tpe(e.index)) match { case (t:UIntType) => false - case (t) => errors += new AccessIndexNotUInt(info) + case (t) => errors.append(new AccessIndexNotUInt(info)) } } case (e:DoPrim) => check_types_primop(e,errors,info) case (e:Mux) => { - if (wt(tpe(e.tval)) != wt(tpe(e.fval))) errors += new MuxSameType(info) - if (!passive(tpe(e))) errors += new MuxPassiveTypes(info) - if (!passive(tpe(e))) errors += new MuxPassiveTypes(info) - if (!(tpe(e.cond).typeof[UIntType])) errors += new MuxCondUInt(info) + if (wt(tpe(e.tval)) != wt(tpe(e.fval))) errors.append(new MuxSameType(info)) + if (!passive(tpe(e))) errors.append(new MuxPassiveTypes(info)) + if (!passive(tpe(e))) errors.append(new MuxPassiveTypes(info)) + if (!(tpe(e.cond).typeof[UIntType])) errors.append(new MuxCondUInt(info)) } case (e:ValidIf) => { - if (!passive(tpe(e))) errors += new ValidIfPassiveTypes(info) - if (!(tpe(e.cond).typeof[UIntType])) errors += new ValidIfCondUInt(info) + if (!passive(tpe(e))) errors.append(new ValidIfPassiveTypes(info)) + if (!(tpe(e.cond).typeof[UIntType])) errors.append(new ValidIfCondUInt(info)) } case (_:UIntValue|_:SIntValue) => false } @@ -479,22 +479,22 @@ object CheckTypes extends Pass with LazyLogging { def check_types_s (s:Stmt) : Stmt = { s map (check_types_e(get_info(s))) match { - case (s:Connect) => if (wt(tpe(s.loc)) != wt(tpe(s.exp))) errors += new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize) - case (s:DefRegister) => if (wt(s.tpe) != wt(tpe(s.init))) errors += new InvalidRegInit(s.info) - case (s:BulkConnect) => if (!bulk_equals(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT) ) errors += new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize) + case (s:Connect) => if (wt(tpe(s.loc)) != wt(tpe(s.exp))) errors.append(new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize)) + case (s:DefRegister) => if (wt(s.tpe) != wt(tpe(s.init))) errors.append(new InvalidRegInit(s.info)) + case (s:BulkConnect) => if (!bulk_equals(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT) ) errors.append(new InvalidConnect(s.info, s.loc.serialize, s.exp.serialize)) case (s:Stop) => { - if (wt(tpe(s.clk)) != wt(ClockType()) ) errors += new ReqClk(s.info) - if (wt(tpe(s.en)) != wt(ut()) ) errors += new EnNotUInt(s.info) + if (wt(tpe(s.clk)) != wt(ClockType()) ) errors.append(new ReqClk(s.info)) + if (wt(tpe(s.en)) != wt(ut()) ) errors.append(new EnNotUInt(s.info)) } case (s:Print)=> { for (x <- s.args ) { - if (wt(tpe(x)) != wt(ut()) && wt(tpe(x)) != wt(st()) ) errors += new PrintfArgNotGround(s.info) + if (wt(tpe(x)) != wt(ut()) && wt(tpe(x)) != wt(st()) ) errors.append(new PrintfArgNotGround(s.info)) } - if (wt(tpe(s.clk)) != wt(ClockType()) ) errors += new ReqClk(s.info) - if (wt(tpe(s.en)) != wt(ut()) ) errors += new EnNotUInt(s.info) + if (wt(tpe(s.clk)) != wt(ClockType()) ) errors.append(new ReqClk(s.info)) + if (wt(tpe(s.en)) != wt(ut()) ) errors.append(new EnNotUInt(s.info)) } - case (s:Conditionally) => if (wt(tpe(s.pred)) != wt(ut()) ) errors += new PredNotUInt(s.info) - case (s:DefNode) => if (!passive(tpe(s.value)) ) errors += new NodePassiveType(s.info) + case (s:Conditionally) => if (wt(tpe(s.pred)) != wt(ut()) ) errors.append(new PredNotUInt(s.info)) + case (s:DefNode) => if (!passive(tpe(s.value)) ) errors.append(new NodePassiveType(s.info)) case (s) => false } s map (check_types_s) @@ -507,7 +507,7 @@ object CheckTypes extends Pass with LazyLogging { case (m:InModule) => check_types_s(m.body) } } - if (errors.nonEmpty) throw new PassExceptions(errors) + errors.trigger c } } @@ -534,7 +534,7 @@ object CheckGenders extends Pass { } def run (c:Circuit): Circuit = { - val errors = ArrayBuffer[PassException]() + val errors = new Errors() def get_kind (e:Expression) : Kind = { (e) match { case (e:WRef) => e.kind @@ -574,14 +574,14 @@ object CheckGenders extends Pass { //println(desired == gender) //if gender != desired and gender != BI-GENDER: (gender,desired) match { - case (MALE, FEMALE) => errors += new WrongGender(info,e.serialize,as_srcsnk(desired),as_srcsnk(gender)) + case (MALE, FEMALE) => errors.append(new WrongGender(info,e.serialize,as_srcsnk(desired),as_srcsnk(gender))) case (FEMALE, MALE) => if ((kindx == PortKind() || kindx == InstanceKind()) && has_flipQ == false) { //; OK! false } else { //; Not Ok! - errors += new WrongGender(info,e.serialize,as_srcsnk(desired),as_srcsnk(gender)) + errors.append(new WrongGender(info,e.serialize,as_srcsnk(desired),as_srcsnk(gender))) } case _ => false } @@ -672,7 +672,7 @@ object CheckGenders extends Pass { case (m:InModule) => check_genders_s(genders)(m.body) } } - if (errors.nonEmpty) throw new PassExceptions(errors) + errors.trigger c } } @@ -684,12 +684,12 @@ object CheckWidths extends Pass { class WidthTooSmall (info:Info,v:String) extends PassException(s"${info} : [module ${mname} Width too small for constant ${v}.") class NegWidthException(info:Info) extends PassException(s"${info}: [module ${mname}] Width cannot be negative or zero.") def run (c:Circuit): Circuit = { - val errors = ArrayBuffer[PassException]() + val errors = new Errors() def check_width_m (m:Module) : Unit = { def check_width_w (info:Info)(w:Width) : Width = { (w) match { - case (w:IntWidth)=> if (w.width <= 0) errors += new NegWidthException(info) - case (w) => errors += new UninferredWidth(info) + case (w:IntWidth)=> if (w.width <= 0) errors.append(new NegWidthException(info)) + case (w) => errors.append(new UninferredWidth(info)) } w } @@ -699,17 +699,17 @@ object CheckWidths extends Pass { (e.width) match { case (w:IntWidth) => if (scala.math.max(1,e.value.bitLength) > w.width) { - errors += new WidthTooSmall(info, serialize(e.value)) + errors.append(new WidthTooSmall(info, serialize(e.value))) } - case (w) => errors += new UninferredWidth(info) + case (w) => errors.append(new UninferredWidth(info)) } check_width_w(info)(e.width) } case (e:SIntValue) => { (e.width) match { case (w:IntWidth) => - if (e.value.bitLength + 1 > w.width) errors += new WidthTooSmall(info, serialize(e.value)) - case (w) => errors += new UninferredWidth(info) + if (e.value.bitLength + 1 > w.width) errors.append(new WidthTooSmall(info, serialize(e.value))) + case (w) => errors.append(new UninferredWidth(info)) } check_width_w(info)(e.width) } @@ -738,7 +738,7 @@ object CheckWidths extends Pass { mname = m.name check_width_m(m) } - if (errors.nonEmpty) throw new PassExceptions(errors) + errors.trigger c } } diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index bc11bc9d..c0d5327f 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -50,6 +50,17 @@ trait Pass extends LazyLogging { // Error handling class PassException(message: String) extends Exception(message) class PassExceptions(exceptions: Seq[PassException]) extends Exception("\n" + exceptions.mkString("\n")) +class Errors { + val errors = ArrayBuffer[PassException]() + def append(pe: PassException) = errors.append(pe) + def trigger = errors.size match { + case 0 => + case 1 => throw errors.head + case _ => + append(new PassException(s"${errors.length} errors detected!")) + throw new PassExceptions(errors) + } +} // These should be distributed into separate files object ToWorkingIR extends Pass { diff --git a/src/test/scala/firrtlTests/CheckSpec.scala b/src/test/scala/firrtlTests/CheckSpec.scala index ea0767bb..5c1b1a67 100644 --- a/src/test/scala/firrtlTests/CheckSpec.scala +++ b/src/test/scala/firrtlTests/CheckSpec.scala @@ -19,7 +19,7 @@ class CheckSpec extends FlatSpec with Matchers { | depth => 32 | read-latency => 0 | write-latency => 1""".stripMargin - intercept[PassExceptions] { + intercept[CheckHighForm.MemWithFlipException] { passes.foldLeft(Parser.parse(input.split("\n").toIterator)) { (c: Circuit, p: Pass) => p.run(c) } diff --git a/src/test/scala/firrtlTests/UnitTests.scala b/src/test/scala/firrtlTests/UnitTests.scala index dac8a40f..98693c61 100644 --- a/src/test/scala/firrtlTests/UnitTests.scala +++ b/src/test/scala/firrtlTests/UnitTests.scala @@ -60,12 +60,11 @@ class UnitTests extends FirrtlFlatSpec { | input y: {a : UInt<1>} | output x: {a : UInt<1>, b : UInt<1>} | x <= y""".stripMargin - val thrown = intercept[PassExceptions] { + intercept[CheckTypes.InvalidConnect] { passes.foldLeft(parse(input)) { (c: Circuit, p: Pass) => p.run(c) } } - assert(thrown.getMessage contains "Type mismatch. Cannot connect") } "Initializing a register with a different type" should "throw an exception" in { @@ -83,7 +82,7 @@ class UnitTests extends FirrtlFlatSpec { | wire x : { valid : UInt<1> } | reg y : { valid : UInt<1>, bits : UInt<3> }, clk with : | reset => (reset, x)""".stripMargin - intercept[PassExceptions] { + intercept[CheckTypes.InvalidRegInit] { passes.foldLeft(parse(input)) { (c: Circuit, p: Pass) => p.run(c) } -- cgit v1.2.3 From 10b392e117682b0868de29b42f9e4e49cf6569d5 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Fri, 29 Apr 2016 10:16:25 -0700 Subject: Remove prefix checking from Check High Form Made obsolete by #120 --- src/main/scala/firrtl/passes/Checks.scala | 33 ------------------------------- 1 file changed, 33 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala index 083a18fd..49effc75 100644 --- a/src/main/scala/firrtl/passes/Checks.scala +++ b/src/main/scala/firrtl/passes/Checks.scala @@ -45,7 +45,6 @@ object CheckHighForm extends Pass with LazyLogging { // Custom Exceptions class NotUniqueException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Reference ${name} does not have a unique name.") - class IsPrefixException(prefix: String) extends PassException(s"${sinfo}: [module ${mname}] Symbol ${prefix} is a prefix.") class InvalidLOCException extends PassException(s"${sinfo}: [module ${mname}] Invalid connect to an expression that is not a reference or a WritePort.") class NegUIntException extends PassException(s"${sinfo}: [module ${mname}] UIntValue cannot be negative.") class UndeclaredReferenceException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Reference ${name} is not declared.") @@ -63,35 +62,6 @@ object CheckHighForm extends Pass with LazyLogging { class BadPrintfTrailingException extends PassException(s"${sinfo}: [module ${mname}] Bad printf format: trailing " + "\"%\"") class BadPrintfIncorrectNumException extends PassException(s"${sinfo}: [module ${mname}] Bad printf format: incorrect number of arguments") - // Trie Datastructure for prefix checking - case class Trie(var children: HashMap[String, Trie], var end: Boolean) { - def empty: Boolean = children.isEmpty - def add(ls: Seq[String]): Boolean = { - var t: Trie = this - var sawEnd = false - for (x <- ls) { - if (t.end) sawEnd = true - if (t.contains(x)) t = t.children(x) - else { - val temp = new Trie(HashMap[String,Trie](),false) - t.children(x) = temp - t = temp - } - } - t.end = true - sawEnd | !t.empty - } - def contains(s: String): Boolean = children.contains(s) - def contains(ls: Seq[String]): Boolean = { - var t: Trie = this - for (x <- ls) { - if (t.contains(x)) t = t.children(x) - else return false - } - t.end - } - } - // Utility functions def hasFlip(t: Type): Boolean = { var has = false @@ -202,7 +172,6 @@ object CheckHighForm extends Pass with LazyLogging { def checkHighFormM(m: Module): Module = { val names = HashMap[String, Boolean]() val mnames = HashMap[String, Boolean]() - val tries = Trie(HashMap[String, Trie](),false) def checkHighFormE(e: Expression): Expression = { def validSubexp(e: Expression): Expression = { e match { @@ -232,8 +201,6 @@ object CheckHighForm extends Pass with LazyLogging { def checkName(name: String): String = { if (names.contains(name)) errors.append(new NotUniqueException(name)) else names(name) = true - val ls: Seq[String] = name.split('$') - if (tries.add(ls)) errors.append(new IsPrefixException(name)) name } sinfo = s.getInfo -- cgit v1.2.3 From 4562e2cb8468d7021320754aeaff395de1a22206 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 1 Jun 2016 22:23:51 -0700 Subject: Suppress "match may not be exhaustive" warning --- src/main/scala/firrtl/Utils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 98edaf4b..a2ca3103 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -630,7 +630,7 @@ object Utils extends LazyLogging { case decl: IsDeclaration => if (decl.name == name) Some(decl) else None case c: Conditionally => val m = (getRootDecl(name)(c.conseq), getRootDecl(name)(c.alt)) - m match { + (m: @unchecked) match { case (Some(decl), None) => Some(decl) case (None, Some(decl)) => Some(decl) case (None, None) => None -- cgit v1.2.3 From 3118db7ce6669cbf7d7fc72690a209f695dbbc06 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Tue, 3 May 2016 23:54:09 -0700 Subject: Guard mem read ports with random data if read addr is out of range Add function for diff assignments for sim and synthesis to VerilogEmitter Fixes #155 --- src/main/scala/firrtl/Emitter.scala | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 17cb9d50..eb4cd9b8 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -55,10 +55,11 @@ object FIRRTLEmitter extends Emitter { } case class VIndent() -case class VRandom() +case object VRandom extends Expression { + def tpe = UIntType(UnknownWidth()) +} class VerilogEmitter extends Emitter { val tab = " " - val ran = VRandom() var w:Option[Writer] = None var mname = "" def wref (n:String,t:Type) = WRef(n,t,ExpKind(),UNKNOWNGENDER) @@ -72,7 +73,7 @@ class VerilogEmitter extends Emitter { def emit (x:Any) = emit2(x,0) def emit2 (x:Any, top:Int) : Unit = { def cast (e:Expression) : Any = { - (tpe(e)) match { + e.tpe match { case (t:UIntType) => e case (t:SIntType) => Seq("$signed(",e,")") case (t:ClockType) => e @@ -89,6 +90,8 @@ class VerilogEmitter extends Emitter { case (e:WSubAccess) => w.get.write(LowerTypes.loweredName(e.exp) + "[" + LowerTypes.loweredName(e.index) + "]") case (e:WSubIndex) => w.get.write(e.serialize) case (_:UIntValue|_:SIntValue) => v_print(e) + case VRandom => w.get.write("$random") + } } case (t:Type) => { @@ -113,7 +116,6 @@ class VerilogEmitter extends Emitter { case (i:Int) => w.get.write(i.toString) case (i:Long) => w.get.write(i.toString) case (t:VIndent) => w.get.write(" ") - case (r:VRandom) => w.get.write("$random") case (s:Seq[Any]) => { s.foreach((x:Any) => emit2(x.as[Any].get, top + 1)) if (top == 0) w.get.write("\n") @@ -308,6 +310,14 @@ class VerilogEmitter extends Emitter { } def assign (e:Expression,value:Expression) = assigns += Seq("assign ",e," = ",value,";") + // Like assign but with different versions for synthesis and simulation + def synSimAssign(e: Expression, syn: Expression, sim: Expression) = { + assigns += Seq("`ifdef SYNTHESIS") + assigns += Seq("assign ", e, " = ", syn, ";") + assigns += Seq("`else") + assigns += Seq("assign ", e, " = ", sim, ";") + assigns += Seq("`endif") + } def update_and_reset(r: Expression, clk: Expression, reset: Expression, init: Expression) = { def addUpdate(e: Expression, tabs: String): Seq[Seq[Any]] = { e match { @@ -349,7 +359,7 @@ class VerilogEmitter extends Emitter { val nx = namespace.newTemp val wx = ((long_BANG(t) + 31) / 32).toInt val tx = SIntType(IntWidth(wx * 32)) - val rand = Seq("{",wx.toString,"{",ran,"}}") + val rand = Seq("{",wx.toString,"{",VRandom,"}}") declare("reg",nx,tx) initials += Seq(wref(nx,tx)," = ",rand,";") Seq(nx,"[",long_BANG(t) - 1,":0]") @@ -486,7 +496,10 @@ class VerilogEmitter extends Emitter { val addrx = delay(addr,s.read_latency,clk) val enx = delay(en,s.read_latency,clk) val mem_port = WSubAccess(mem,addrx,s.data_type,UNKNOWNGENDER) - assign(data,mem_port) + val depthValue = UIntValue(s.depth, IntWidth(BigInt(s.depth).bitLength)) + val garbageGuard = DoPrim(GREATER_EQ_OP, Seq(addrx, depthValue), Seq(), UnknownType()) + val garbageMux = Mux(garbageGuard, VRandom, mem_port, UnknownType()) + synSimAssign(data, mem_port, garbageMux) } for (w <- s.writers ) { -- cgit v1.2.3 From e5ddfe2a356810b27ad419fe35b41000767ad972 Mon Sep 17 00:00:00 2001 From: Stephen Twigg Date: Tue, 24 May 2016 15:04:28 -0700 Subject: Fix bug in FIRRTL width inference, refactor associated functions When folding over lists for MinWidth and MaxWidth, would assume 0 as a start value. 0 persists through MinWidth resulting in under-constraining The functions were also refactored to be more readable and aligned with scala style/best practices. --- src/main/scala/firrtl/passes/Passes.scala | 74 +++++++++++++++---------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index c0d5327f..4ed152a4 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -482,47 +482,47 @@ object InferWidths extends Pass { case (t:ClockType) => IntWidth(1) case (t) => error("No width!"); IntWidth(-1) } } def width_BANG (e:Expression) : Width = width_BANG(tpe(e)) - def reduce_var_widths (c:Circuit,h:LinkedHashMap[String,Width]) : Circuit = { - def evaluate (w:Width) : Width = { - def apply_2 (a:Option[BigInt],b:Option[BigInt], f: (BigInt,BigInt) => BigInt) : Option[BigInt] = { - (a,b) match { - case (a:Some[BigInt],b:Some[BigInt]) => Some(f(a.get,b.get)) - case (a,b) => None } } - def apply_1 (a:Option[BigInt], f: (BigInt) => BigInt) : Option[BigInt] = { - (a) match { - case (a:Some[BigInt]) => Some(f(a.get)) - case (a) => None } } - def apply_l (l:Seq[Option[BigInt]],f:(BigInt,BigInt) => BigInt) : Option[BigInt] = { - if (l.size == 0) Some(BigInt(0)) else apply_2(l.head,apply_l(l.tail,f),f) - } - def max (a:BigInt,b:BigInt) : BigInt = if (a >= b) a else b - def min (a:BigInt,b:BigInt) : BigInt = if (a >= b) b else a - def pow (a:BigInt,b:BigInt) : BigInt = BigInt((scala.math.pow(a.toDouble,b.toDouble) - 1).toLong) - def solve (w:Width) : Option[BigInt] = { - (w) match { - case (w:VarWidth) => { - val wx = h.get(w.name) - (wx) match { - case (wx:Some[Width]) => { - wx.get match { - case (v:VarWidth) => None - case (v) => solve(v) }} - case (None) => None }} - case (w:MaxWidth) => apply_l(w.args.map(solve _),max) - case (w:MinWidth) => apply_l(w.args.map(solve _),min) - case (w:PlusWidth) => apply_2(solve(w.arg1),solve(w.arg2),{_ + _}) - case (w:MinusWidth) => apply_2(solve(w.arg1),solve(w.arg2),{_ - _}) - case (w:ExpWidth) => apply_2(Some(BigInt(2)),solve(w.arg1),pow) - case (w:IntWidth) => Some(w.width) - case (w) => println(w); error("Shouldn't be here"); None; - } + + def reduce_var_widths(c: Circuit, h: LinkedHashMap[String,Width]): Circuit = { + def evaluate(w: Width): Width = { + def map2(a: Option[BigInt], b: Option[BigInt], f: (BigInt,BigInt) => BigInt): Option[BigInt] = + for (a_num <- a; b_num <- b) yield f(a_num, b_num) + def reduceOptions(l: Seq[Option[BigInt]], f: (BigInt,BigInt) => BigInt): Option[BigInt] = + l.reduce(map2(_, _, f)) + + // This function shouldn't be necessary + // Added as protection in case a constraint accidentally uses MinWidth/MaxWidth + // without any actual Widths. This should be elevated to an earlier error + def forceNonEmpty(in: Seq[Option[BigInt]]): Seq[Option[BigInt]] = + if(in.isEmpty) Seq(None) + else in + + def max(a: BigInt, b: BigInt): BigInt = if (a >= b) a else b + def min(a: BigInt, b: BigInt): BigInt = if (a >= b) b else a + def pow_minus_one(a: BigInt, b: BigInt): BigInt = a.pow(b.toInt) - 1 + + def solve(w: Width): Option[BigInt] = w match { + case (w: VarWidth) => + for{ + v <- h.get(w.name) if !v.isInstanceOf[VarWidth] + result <- solve(v) + } yield result + case (w: MaxWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _)), max) + case (w: MinWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _)), min) + case (w: PlusWidth) => map2(solve(w.arg1), solve(w.arg2), {_ + _}) + case (w: MinusWidth) => map2(solve(w.arg1), solve(w.arg2), {_ - _}) + case (w: ExpWidth) => map2(Some(BigInt(2)), solve(w.arg1), pow_minus_one) + case (w: IntWidth) => Some(w.width) + case (w) => println(w); error("Shouldn't be here"); None; } + val s = solve(w) (s) match { - case (s:Some[BigInt]) => IntWidth(s.get) - case (s) => w } + case Some(s) => IntWidth(s) + case (s) => w + } } - + def reduce_var_widths_w (w:Width) : Width = { //println-all-debug(["REPLACE: " w]) val wx = evaluate(w) -- cgit v1.2.3 From f5a3b381dd64302817f3ad0c3d35d1ae3f0106db Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 7 Jun 2016 10:02:01 -0700 Subject: Fix non-thread safe Serialize by splitting it into class and object --- src/main/scala/firrtl/Serialize.scala | 30 +++++++++++++++++------------- src/main/scala/firrtl/passes/Checks.scala | 8 +++++--- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/Serialize.scala b/src/main/scala/firrtl/Serialize.scala index 0229bb57..1735c270 100644 --- a/src/main/scala/firrtl/Serialize.scala +++ b/src/main/scala/firrtl/Serialize.scala @@ -31,25 +31,29 @@ import firrtl.PrimOps._ import firrtl.Utils._ private object Serialize { - def serialize(root: AST): String = { + lazy val ser = new Serialize root match { - case r: PrimOp => serialize(r) - case r: Expression => serialize(r) - case r: Stmt => serialize(r) - case r: Width => serialize(r) - case r: Flip => serialize(r) - case r: Field => serialize(r) - case r: Type => serialize(r) - case r: Direction => serialize(r) - case r: Port => serialize(r) - case r: Module => serialize(r) - case r: Circuit => serialize(r) - case r: StringLit => serialize(r) + case r: PrimOp => ser.serialize(r) + case r: Expression => ser.serialize(r) + case r: Stmt => ser.serialize(r) + case r: Width => ser.serialize(r) + case r: Flip => ser.serialize(r) + case r: Field => ser.serialize(r) + case r: Type => ser.serialize(r) + case r: Direction => ser.serialize(r) + case r: Port => ser.serialize(r) + case r: Module => ser.serialize(r) + case r: Circuit => ser.serialize(r) + case r: StringLit => ser.serialize(r) case _ => throw new Exception("serialize called on unknown AST node!") } } + /** Creates new instance of Serialize */ + def apply() = new Serialize +} +class Serialize { def serialize(bi: BigInt): String = if (bi < BigInt(0)) "\"h" + bi.toString(16).substring(1) + "\"" else "\"h" + bi.toString(16) + "\"" diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala index 083a18fd..15f17453 100644 --- a/src/main/scala/firrtl/passes/Checks.scala +++ b/src/main/scala/firrtl/passes/Checks.scala @@ -681,7 +681,9 @@ object CheckWidths extends Pass { def name = "Width Check" var mname = "" class UninferredWidth (info:Info) extends PassException(s"${info} : [module ${mname}] Uninferred width.") - class WidthTooSmall (info:Info,v:String) extends PassException(s"${info} : [module ${mname} Width too small for constant ${v}.") + class WidthTooSmall(info: Info, b: BigInt) extends PassException( + s"$info : [module $mname] Width too small for constant " + + Serialize().serialize(b) + ".") class NegWidthException(info:Info) extends PassException(s"${info}: [module ${mname}] Width cannot be negative or zero.") def run (c:Circuit): Circuit = { val errors = new Errors() @@ -699,7 +701,7 @@ object CheckWidths extends Pass { (e.width) match { case (w:IntWidth) => if (scala.math.max(1,e.value.bitLength) > w.width) { - errors.append(new WidthTooSmall(info, serialize(e.value))) + errors.append(new WidthTooSmall(info, e.value)) } case (w) => errors.append(new UninferredWidth(info)) } @@ -708,7 +710,7 @@ object CheckWidths extends Pass { case (e:SIntValue) => { (e.width) match { case (w:IntWidth) => - if (e.value.bitLength + 1 > w.width) errors.append(new WidthTooSmall(info, serialize(e.value))) + if (e.value.bitLength + 1 > w.width) errors.append(new WidthTooSmall(info, e.value)) case (w) => errors.append(new UninferredWidth(info)) } check_width_w(info)(e.width) -- cgit v1.2.3 From c15ab1a3e362cb5400cb5d503a721be751de2a94 Mon Sep 17 00:00:00 2001 From: azidar Date: Wed, 8 Jun 2016 11:04:42 -0700 Subject: Fix for bug introduced in #174 Addresses #184 Problem was that the width inferencer must assume a minimal width for self-referencing widths contained in a MaxWidth. Otherwise, it cannot solve the constraint. --- src/main/scala/firrtl/passes/Passes.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index 4ed152a4..abd758bf 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -493,8 +493,8 @@ object InferWidths extends Pass { // This function shouldn't be necessary // Added as protection in case a constraint accidentally uses MinWidth/MaxWidth // without any actual Widths. This should be elevated to an earlier error - def forceNonEmpty(in: Seq[Option[BigInt]]): Seq[Option[BigInt]] = - if(in.isEmpty) Seq(None) + def forceNonEmpty(in: Seq[Option[BigInt]], default: Option[BigInt]): Seq[Option[BigInt]] = + if(in.isEmpty) Seq(default) else in def max(a: BigInt, b: BigInt): BigInt = if (a >= b) a else b @@ -507,8 +507,8 @@ object InferWidths extends Pass { v <- h.get(w.name) if !v.isInstanceOf[VarWidth] result <- solve(v) } yield result - case (w: MaxWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _)), max) - case (w: MinWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _)), min) + case (w: MaxWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _), Some(BigInt(0))), max) + case (w: MinWidth) => reduceOptions(forceNonEmpty(w.args.map(solve _), None), min) case (w: PlusWidth) => map2(solve(w.arg1), solve(w.arg2), {_ + _}) case (w: MinusWidth) => map2(solve(w.arg1), solve(w.arg2), {_ - _}) case (w: ExpWidth) => map2(Some(BigInt(2)), solve(w.arg1), pow_minus_one) -- cgit v1.2.3