From 117d82b38cc49c53422fe77e5c697792faaa6486 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Mon, 12 Sep 2016 21:12:01 -0700 Subject: Add unapply for GroundType --- src/main/scala/firrtl/ir/IR.scala | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala index 8f1cabf6..cdbf2fd7 100644 --- a/src/main/scala/firrtl/ir/IR.scala +++ b/src/main/scala/firrtl/ir/IR.scala @@ -329,6 +329,9 @@ abstract class GroundType extends Type { val width: Width def mapType(f: Type => Type): Type = this } +object GroundType { + def unapply(ground: GroundType): Option[Width] = Some(ground.width) +} abstract class AggregateType extends Type { def mapWidth(f: Width => Width): Type = this } -- cgit v1.2.3 From 7f12a07d941bd08749ef350654fe9a324b882a6b Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Mon, 12 Sep 2016 21:12:35 -0700 Subject: Change bitWidth to support ClockType Match on GroundType instead of UIntType and SIntType --- src/main/scala/firrtl/passes/MemUtils.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/MemUtils.scala b/src/main/scala/firrtl/passes/MemUtils.scala index b235213a..adbf23e5 100644 --- a/src/main/scala/firrtl/passes/MemUtils.scala +++ b/src/main/scala/firrtl/passes/MemUtils.scala @@ -83,8 +83,7 @@ object bitWidth { def widthOf(dt: Type): BigInt = dt match { case t: VectorType => t.size * bitWidth(t.tpe) case t: BundleType => t.fields.map(f => bitWidth(f.tpe)).foldLeft(BigInt(0))(_+_) - case UIntType(IntWidth(width)) => width - case SIntType(IntWidth(width)) => width + case GroundType(IntWidth(width)) => width case t => error("Unknown type encountered in bitWidth!") } } -- cgit v1.2.3 From 6c93f5e688554ff3432715d206351d2d84341eed Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Mon, 12 Sep 2016 15:23:21 -0700 Subject: Change Legalize Shift Right to respect SInt Fix bug where Legalize was generating a bit select for SInts without then casting to SInt Fixes #169 --- src/main/scala/firrtl/passes/Passes.scala | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index b9808485..660b2d1f 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -211,23 +211,22 @@ object ExpandConnects extends Pass { // TODO replace UInt with zero-width wire instead object Legalize extends Pass { def name = "Legalize" - def legalizeShiftRight (e: DoPrim): Expression = e.op match { - case Shr => { - val amount = e.consts.head.toInt - val width = long_BANG(e.args.head.tpe) - lazy val msb = width - 1 - if (amount >= width) { - e.tpe match { - case t: UIntType => UIntLiteral(0, IntWidth(1)) - case t: SIntType => - DoPrim(Bits, e.args, Seq(msb, msb), SIntType(IntWidth(1))) - case t => error(s"Unsupported type ${t} for Primop Shift Right") - } - } else { - e + private def legalizeShiftRight(e: DoPrim): Expression = { + require(e.op == Shr) + val amount = e.consts.head.toInt + val width = bitWidth(e.args.head.tpe) + lazy val msb = width - 1 + if (amount >= width) { + e.tpe match { + case UIntType(_) => UIntLiteral(0, IntWidth(1)) + case SIntType(_) => + val bits = DoPrim(Bits, e.args, Seq(msb, msb), UIntType(IntWidth(1))) + DoPrim(AsSInt, Seq(bits), Seq.empty, SIntType(IntWidth(1))) + case t => error(s"Unsupported type ${t} for Primop Shift Right") } + } else { + e } - case _ => e } def legalizeConnect(c: Connect): Statement = { val t = c.loc.tpe @@ -242,11 +241,12 @@ object Legalize extends Pass { } } def run (c: Circuit): Circuit = { - def legalizeE (e: Expression): Expression = { - e map (legalizeE) match { - case e: DoPrim => legalizeShiftRight(e) - case e => e + def legalizeE(expr: Expression): Expression = expr map legalizeE match { + case prim: DoPrim => prim.op match { + case Shr => legalizeShiftRight(prim) + case _ => prim } + case e => e // respect pre-order traversal } def legalizeS (s: Statement): Statement = { val legalizedStmt = s match { -- cgit v1.2.3 From f7dd234f7c5a2dc03c42640db11b1d6509108643 Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 17 May 2016 14:27:29 -0700 Subject: Change Legalize Connect to respect SInt Legalize will wrap the rhs of a connect statement with a bit select primop if the lhs is of smaller width than the rhs. This bit select is now wrapped in a asSInt cast if the original rhs was an SInt so that is has the correct type. Fixes #173 --- src/main/scala/firrtl/passes/Passes.scala | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index 660b2d1f..0405701f 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -228,16 +228,18 @@ object Legalize extends Pass { e } } - def legalizeConnect(c: Connect): Statement = { + private def legalizeConnect(c: Connect): Statement = { val t = c.loc.tpe - val w = long_BANG(t) - if (w >= long_BANG(c.expr.tpe)) c - else { - val newType = t match { - case _: UIntType => UIntType(IntWidth(w)) - case _: SIntType => SIntType(IntWidth(w)) + val w = bitWidth(t) + if (w >= bitWidth(c.expr.tpe)) { + c + } else { + val bits = DoPrim(Bits, Seq(c.expr), Seq(w - 1, 0), UIntType(IntWidth(w))) + val expr = t match { + case UIntType(_) => bits + case SIntType(_) => DoPrim(AsSInt, Seq(bits), Seq(), SIntType(IntWidth(w))) } - Connect(c.info, c.loc, DoPrim(Bits, Seq(c.expr), Seq(w-1, 0), newType)) + Connect(c.info, c.loc, expr) } } def run (c: Circuit): Circuit = { -- cgit v1.2.3 From 9edf656e11084958d9e90807a4740a57b83babfe Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 18 May 2016 12:02:52 -0700 Subject: Legalize bit select. Run Legalize after PadWidths. Bit selecting a literal resulted in invalid Verilog. Legalize now deals with this by replacing any bits select of UInt or SInt literals with a new literal composed of the selected bits. Legalize also is now run after PadWidths because that pass introduces this issue. Fixes #170 --- src/main/scala/firrtl/LoweringCompilers.scala | 2 +- src/main/scala/firrtl/passes/Passes.scala | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala index c8430d2b..4d40d9a8 100644 --- a/src/main/scala/firrtl/LoweringCompilers.scala +++ b/src/main/scala/firrtl/LoweringCompilers.scala @@ -124,7 +124,6 @@ class HighFirrtlToMiddleFirrtl () extends Transform with SimpleRun { // TODO(izraelevitz): Create RenameMap from RemoveCHIRRTL class MiddleFirrtlToLowFirrtl () extends Transform with SimpleRun { val passSeq = Seq( - passes.Legalize, passes.LowerTypes, passes.ResolveKinds, passes.InferTypes, @@ -146,6 +145,7 @@ class EmitVerilogFromLowFirrtl (val writer: Writer) extends Transform with Simpl passes.ConstProp, passes.PadWidths, passes.ConstProp, + passes.Legalize, passes.VerilogWrap, passes.SplitExpressions, passes.CommonSubexpressionElimination, diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index 0405701f..66437556 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -228,6 +228,16 @@ object Legalize extends Pass { e } } + private def legalizeBits(expr: DoPrim): Expression = { + lazy val (hi, low) = (expr.consts(0), expr.consts(1)) + lazy val mask = (BigInt(1) << (hi - low + 1).toInt) - 1 + lazy val width = IntWidth(hi - low + 1) + expr.args.head match { + case UIntLiteral(value, _) => UIntLiteral((value >> low.toInt) & mask, width) + case SIntLiteral(value, _) => SIntLiteral((value >> low.toInt) & mask, width) + case _ => expr + } + } private def legalizeConnect(c: Connect): Statement = { val t = c.loc.tpe val w = bitWidth(t) @@ -246,6 +256,7 @@ object Legalize extends Pass { def legalizeE(expr: Expression): Expression = expr map legalizeE match { case prim: DoPrim => prim.op match { case Shr => legalizeShiftRight(prim) + case Bits => legalizeBits(prim) case _ => prim } case e => e // respect pre-order traversal -- cgit v1.2.3 From 654f1130b604d74c0a194b2598d70111583b442e Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 17 May 2016 14:39:20 -0700 Subject: Cast bit select of SInt in PadWidths to SInt Fixes #172 --- src/main/scala/firrtl/passes/PadWidths.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/PadWidths.scala b/src/main/scala/firrtl/passes/PadWidths.scala index 4cdcae59..1a134d11 100644 --- a/src/main/scala/firrtl/passes/PadWidths.scala +++ b/src/main/scala/firrtl/passes/PadWidths.scala @@ -18,11 +18,18 @@ object PadWidths extends Pass { case t: SIntType => SIntType(IntWidth(i)) // default case should never be reached } - if (i > width(e)) + if (i > width(e)) { DoPrim(Pad, Seq(e), Seq(i), tx) - else if (i < width(e)) - DoPrim(Bits, Seq(e), Seq(i - 1, 0), tx) - else e + } else if (i < width(e)) { + val e2 = DoPrim(Bits, Seq(e), Seq(i - 1, 0), UIntType(IntWidth(i))) + // Bit Select always returns UInt, cast if selecting from SInt + e.tpe match { + case UIntType(_) => e2 + case SIntType(_) => DoPrim(AsSInt, Seq(e2), Seq.empty, SIntType(IntWidth(i))) + } + } else { + e + } } // Recursive, updates expression so children exp's have correct widths private def onExp(e: Expression): Expression = { -- cgit v1.2.3 From 5e62c6ba87e398509c1bc7a3d987c7c2e0f7abc4 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 18 May 2016 12:08:08 -0700 Subject: Add legalization of pad operation on literals. Performing a pad on SInt literals results in linting warnings in Verilator. This commit replaces pad operations on literal values with a literal of the correct width. --- src/main/scala/firrtl/passes/Passes.scala | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index 66437556..d5d9a3b6 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -238,6 +238,13 @@ object Legalize extends Pass { case _ => expr } } + private def legalizePad(expr: DoPrim): Expression = expr.args.head match { + case UIntLiteral(value, IntWidth(width)) if (width < expr.consts.head) => + UIntLiteral(value, IntWidth(expr.consts.head)) + case SIntLiteral(value, IntWidth(width)) if (width < expr.consts.head) => + SIntLiteral(value, IntWidth(expr.consts.head)) + case _ => expr + } private def legalizeConnect(c: Connect): Statement = { val t = c.loc.tpe val w = bitWidth(t) @@ -256,6 +263,7 @@ object Legalize extends Pass { def legalizeE(expr: Expression): Expression = expr map legalizeE match { case prim: DoPrim => prim.op match { case Shr => legalizeShiftRight(prim) + case Pad => legalizePad(prim) case Bits => legalizeBits(prim) case _ => prim } -- cgit v1.2.3 From 9a68008856f390bdc3be858f9cce5ed484cdb68f Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 18 May 2016 11:59:11 -0700 Subject: Add LegalizeSpec for testing Verilog Legalization pass --- src/test/resources/passes/Legalize/Legalize.fir | 41 +++++++++++++++++++++++++ src/test/scala/firrtlTests/LegalizeSpec.scala | 38 +++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/test/resources/passes/Legalize/Legalize.fir create mode 100644 src/test/scala/firrtlTests/LegalizeSpec.scala (limited to 'src') diff --git a/src/test/resources/passes/Legalize/Legalize.fir b/src/test/resources/passes/Legalize/Legalize.fir new file mode 100644 index 00000000..6e27a0bf --- /dev/null +++ b/src/test/resources/passes/Legalize/Legalize.fir @@ -0,0 +1,41 @@ + +circuit Legalize : + module Legalize : + input clk : Clock + input reset : UInt<1> + + ; Count till done + node done = UInt(6) + reg count : UInt<16>, clk with : + reset => (reset, UInt(0)) + when neq(count, done) : + count <= add(count, UInt(1)) + when not(reset) : + when eq(count, done) : + stop(clk, UInt(1), 0) + + ; Begin Test + ; Check assignment to smaller width + node x = UInt<32>("hdeadbeef") + wire y : UInt<16> + y <- x + when neq(y, UInt("hbeef")) : + printf(clk, UInt(1), "Assertion failed!\n y != beef\n") + stop(clk, UInt(1), 1) + + ; Check bit select of literal + node b = bits(UInt("hd0"), 7, 5) + node b2 = bits(UInt("h9"), 3, 3) + when neq(b, UInt(6)) : + printf(clk, UInt(1), "Assertion failed!\n b != 6\n") + stop(clk, UInt(1), 1) + when neq(b2, UInt(1)) : + printf(clk, UInt(1), "Assertion failed!\n b2 != 1\n") + stop(clk, UInt(1), 1) + + ; Check padding of literal + node bar = pad(SInt(-1), 16) + node bar_15 = bits(bar, 15, 15) + when neq(bar_15, UInt(1)) : + printf(clk, UInt(1), "Assertion failed!\n bar_15 != 0\n") + stop(clk, UInt(1), 1) diff --git a/src/test/scala/firrtlTests/LegalizeSpec.scala b/src/test/scala/firrtlTests/LegalizeSpec.scala new file mode 100644 index 00000000..781f93d7 --- /dev/null +++ b/src/test/scala/firrtlTests/LegalizeSpec.scala @@ -0,0 +1,38 @@ +/* +Copyright (c) 2014 - 2016 The Regents of the University of +California (Regents). All Rights Reserved. Redistribution and use in +source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF +ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION +TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. +*/ + +package firrtlTests + +import firrtl._ + +class LegalizeSpec extends FirrtlFlatSpec { + behavior of "Legalize" + + it should "compile and run" in { + runFirrtlTest("Legalize", "/passes/Legalize") + } +} -- cgit v1.2.3