diff options
19 files changed, 242 insertions, 134 deletions
diff --git a/src/main/resources/top.cpp b/src/main/resources/top.cpp index 075d7085..8bfe2a99 100644 --- a/src/main/resources/top.cpp +++ b/src/main/resources/top.cpp @@ -44,10 +44,10 @@ int main(int argc, char** argv) { top->reset = 0; // Deassert reset } if ((main_time % 10) == 1) { - top->clock = 1; // Toggle clock + top->clk = 1; // Toggle clock } if ((main_time % 10) == 6) { - top->clock = 0; + top->clk = 0; } top->eval(); // Evaluate model #if VM_TRACE @@ -69,10 +69,10 @@ int main(int argc, char** argv) { vluint64_t end_time = main_time + 100; while (main_time < end_time) { if ((main_time % 10) == 1) { - top->clock = 1; // Toggle clock + top->clk = 1; // Toggle clock } if ((main_time % 10) == 6) { - top->clock = 0; + top->clk = 0; } top->eval(); // Evaluate model #if VM_TRACE diff --git a/src/main/scala/Chisel/Aggregate.scala b/src/main/scala/Chisel/Aggregate.scala index 35b8b4e5..3df48052 100644 --- a/src/main/scala/Chisel/Aggregate.scala +++ b/src/main/scala/Chisel/Aggregate.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -103,21 +103,16 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) private val self = IndexedSeq.fill(length)(gen) - override def <> (that: Data): Unit = that match { - case _: Vec[_] => this bulkConnect that - case _ => this badConnect that - } + override def <> (that: Data): Unit = this := that - /** Weak bulk connect, assigning elements in this Vec from elements in a Seq. + /** Strong bulk connect, assigning elements in this Vec from elements in a Seq. * - * @note length mismatches silently ignored + * @note the length of this Vec must match the length of the input Seq */ - def <> (that: Seq[T]): Unit = - for ((a, b) <- this zip that) - a <> b + def <> (that: Seq[T]): Unit = this := that // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data - def <> (that: Vec[T]): Unit = this bulkConnect that + def <> (that: Vec[T]): Unit = this := that.asInstanceOf[Data] override def := (that: Data): Unit = that match { case _: Vec[_] => this connect that @@ -141,7 +136,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) */ def apply(idx: UInt): T = { val x = gen - pushCommand(DefAccessor(x, Node(this), NO_DIR, idx.ref)) + x.setRef(this, idx) x } @@ -156,7 +151,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) def write(idx: UInt, data: T): Unit = apply(idx) := data override def cloneType: this.type = - Vec(gen, length).asInstanceOf[this.type] + Vec(length, gen).asInstanceOf[this.type] private val t = gen private[Chisel] def toType: String = s"${t.toType}[$length]" @@ -331,7 +326,7 @@ class Bundle extends Aggregate(NO_DIR) { try { constructor.newInstance(_parent.get).asInstanceOf[this.type] } catch { - case _: java.lang.reflect.InvocationTargetException => + case _: java.lang.reflect.InvocationTargetException | _: java.lang.IllegalArgumentException => Builder.error(s"Parameterized Bundle ${this.getClass} needs cloneType method. You are probably using " + "an anonymous Bundle object that captures external state and hence is un-cloneTypeable") this diff --git a/src/main/scala/Chisel/BitPat.scala b/src/main/scala/Chisel/BitPat.scala index b4138992..a1bf1985 100644 --- a/src/main/scala/Chisel/BitPat.scala +++ b/src/main/scala/Chisel/BitPat.scala @@ -75,5 +75,6 @@ object BitPat { sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) { def getWidth: Int = width def === (other: UInt): Bool = UInt(value) === (other & UInt(mask)) - def != (other: UInt): Bool = !(this === other) + def =/= (other: UInt): Bool = !(this === other) + def != (other: UInt): Bool = this =/= other } diff --git a/src/main/scala/Chisel/Bits.scala b/src/main/scala/Chisel/Bits.scala index e001f864..b800644d 100644 --- a/src/main/scala/Chisel/Bits.scala +++ b/src/main/scala/Chisel/Bits.scala @@ -4,15 +4,13 @@ package Chisel import internal._ import internal.Builder.pushOp -import firrtl._ +import internal.firrtl._ import firrtl.PrimOp._ /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. */ -abstract class Element(dirArg: Direction, val width: Width) extends Data(dirArg) { - private[Chisel] def flatten: IndexedSeq[UInt] = IndexedSeq(toBits) -} +abstract class Element(dirArg: Direction, val width: Width) extends Data(dirArg) /** A data type for values represented by a single bitvector. Provides basic * bitwise operations. @@ -25,10 +23,30 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: private[Chisel] def fromInt(x: BigInt): this.type + private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this) + def cloneType: this.type = cloneTypeWidth(width) override def <> (that: Data): Unit = this := that + def tail(n: Int): UInt = { + val w = width match { + case KnownWidth(x) => + require(x >= n, s"Can't tail($n) for width $x < $n") + Width(x - n) + case UnknownWidth() => Width() + } + binop(UInt(width = w), TailOp, n) + } + + def head(n: Int): UInt = { + width match { + case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n") + case UnknownWidth() => + } + binop(UInt(width = n), HeadOp, n) + } + /** Returns the specified bit on this wire as a [[Bool]], statically * addressed. */ @@ -39,7 +57,7 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: if (isLit()) { Bool(((litValue() >> x.toInt) & 1) == 1) } else { - pushOp(DefPrim(Bool(), BitSelectOp, this.ref, ILit(x))) + pushOp(DefPrim(Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) } } @@ -92,9 +110,6 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: private[Chisel] def redop(op: PrimOp): Bool = pushOp(DefPrim(Bool(), op, this.ref)) - /** Returns this wire bitwise-inverted. */ - def unary_~ : this.type = unop(cloneTypeWidth(width), BitNotOp) - /** Returns this wire zero padded up to the specified width. * * @note for SInts only, this does sign extension @@ -279,19 +294,22 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi def unary_-% : UInt = UInt(0) -% this def +& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), AddOp, other) def + (other: UInt): UInt = this +% other - def +% (other: UInt): UInt = binop(UInt(this.width max other.width), AddModOp, other) + def +% (other: UInt): UInt = (this +& other) tail 1 def -& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), SubOp, other) def - (other: UInt): UInt = this -% other - def -% (other: UInt): UInt = binop(UInt(this.width max other.width), SubModOp, other) + def -% (other: UInt): UInt = (this -& other) tail 1 def * (other: UInt): UInt = binop(UInt(this.width + other.width), TimesOp, other) def * (other: SInt): SInt = other * this def / (other: UInt): UInt = binop(UInt(this.width), DivideOp, other) - def % (other: UInt): UInt = binop(UInt(this.width), ModOp, other) + def % (other: UInt): UInt = binop(UInt(this.width), RemOp, other) def & (other: UInt): UInt = binop(UInt(this.width max other.width), BitAndOp, other) def | (other: UInt): UInt = binop(UInt(this.width max other.width), BitOrOp, other) def ^ (other: UInt): UInt = binop(UInt(this.width max other.width), BitXorOp, other) + /** Returns this wire bitwise-inverted. */ + def unary_~ : UInt = unop(UInt(width = width), BitNotOp) + // REVIEW TODO: Can this be defined on Bits? def orR: Bool = this != UInt(0) def andR: Bool = ~this === UInt(0) @@ -321,6 +339,7 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi def === (that: BitPat): Bool = that === this def != (that: BitPat): Bool = that != this + def =/= (that: BitPat): Bool = that =/= this /** Returns this UInt as a [[SInt]] with an additional zero in the MSB. */ @@ -409,21 +428,24 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non /** add (default - no growth) operator */ def + (other: SInt): SInt = this +% other /** add (no growth) operator */ - def +% (other: SInt): SInt = binop(SInt(this.width max other.width), AddModOp, other) + def +% (other: SInt): SInt = (this +& other).tail(1).asSInt /** subtract (width +1) operator */ def -& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), SubOp, other) /** subtract (default - no growth) operator */ def - (other: SInt): SInt = this -% other /** subtract (no growth) operator */ - def -% (other: SInt): SInt = binop(SInt(this.width max other.width), SubModOp, other) + def -% (other: SInt): SInt = (this -& other).tail(1).asSInt def * (other: SInt): SInt = binop(SInt(this.width + other.width), TimesOp, other) def * (other: UInt): SInt = binop(SInt(this.width + other.width), TimesOp, other) def / (other: SInt): SInt = binop(SInt(this.width), DivideOp, other) - def % (other: SInt): SInt = binop(SInt(this.width), ModOp, other) + def % (other: SInt): SInt = binop(SInt(this.width), RemOp, other) - def & (other: SInt): SInt = binop(SInt(this.width max other.width), BitAndOp, other) - def | (other: SInt): SInt = binop(SInt(this.width max other.width), BitOrOp, other) - def ^ (other: SInt): SInt = binop(SInt(this.width max other.width), BitXorOp, other) + def & (other: SInt): SInt = binop(UInt(this.width max other.width), BitAndOp, other).asSInt + def | (other: SInt): SInt = binop(UInt(this.width max other.width), BitOrOp, other).asSInt + def ^ (other: SInt): SInt = binop(UInt(this.width max other.width), BitXorOp, other).asSInt + + /** Returns this wire bitwise-inverted. */ + def unary_~ : SInt = unop(UInt(width = width), BitNotOp).asSInt def < (other: SInt): Bool = compop(LessOp, other) def > (other: SInt): Bool = compop(GreaterOp, other) @@ -431,7 +453,7 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non def >= (other: SInt): Bool = compop(GreaterEqOp, other) def != (other: SInt): Bool = compop(NotEqualOp, other) def === (other: SInt): Bool = compop(EqualOp, other) - def abs(): UInt = Mux(this < SInt(0), (-this).toUInt, this.toUInt) + def abs(): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) def << (other: Int): SInt = binop(SInt(this.width + other), ShiftLeftOp, other) def << (other: BigInt): SInt = this << other.toInt @@ -489,6 +511,9 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi def | (other: Bool): Bool = binop(Bool(), BitOrOp, other) def ^ (other: Bool): Bool = binop(Bool(), BitXorOp, other) + /** Returns this wire bitwise-inverted. */ + override def unary_~ : Bool = unop(Bool(), BitNotOp) + /** Outputs the logical OR of two Bools. */ def || (that: Bool): Bool = this | that @@ -526,21 +551,20 @@ object Mux { case (c: UInt, a: Bool) => doMux(cond, c, a << 0).asInstanceOf[T] case (c: Bool, a: UInt) => doMux(cond, c << 0, a).asInstanceOf[T] case (c: Bits, a: Bits) => doMux(cond, c, a).asInstanceOf[T] - // FIRRTL doesn't support Mux for aggregates, so use a when instead - case _ => doWhen(cond, con, alt) + case _ => doAggregateMux(cond, con, alt) } - private def doMux[T <: Bits](cond: Bool, con: T, alt: T): T = { + private def doMux[T <: Data](cond: Bool, con: T, alt: T): T = { require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}") val d = alt.cloneTypeWidth(con.width max alt.width) pushOp(DefPrim(d, MultiplexOp, cond.ref, con.ref, alt.ref)) } - // This returns an lvalue, which it most definitely should not - private def doWhen[T <: Data](cond: Bool, con: T, alt: T): T = { + + private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T): T = { require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}") - val res = Wire(t = alt.cloneTypeWidth(con.width max alt.width), init = alt) - when (cond) { res := con } - res + for ((c, a) <- con.flatten zip alt.flatten) + require(c.width == a.width, "can't Mux between aggregates of different width") + doMux(cond, con, alt) } } diff --git a/src/main/scala/Chisel/CoreUtil.scala b/src/main/scala/Chisel/CoreUtil.scala index 7077c9c1..eed90410 100644 --- a/src/main/scala/Chisel/CoreUtil.scala +++ b/src/main/scala/Chisel/CoreUtil.scala @@ -4,7 +4,7 @@ package Chisel import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ object assert { /** Checks for a condition to be valid in the circuit at all times. If the @@ -43,13 +43,13 @@ object assert { /** An elaboration-time assertion, otherwise the same as the above run-time * assertion. */ def apply(cond: Boolean, message: String) { - apply(Bool(cond), message) + Predef.assert(cond, message) } /** A workaround for default-value overloading problems in Scala, just * 'assert(cond, "")' */ def apply(cond: Boolean) { - apply(cond, "") + Predef.assert(cond, "") } } diff --git a/src/main/scala/Chisel/Data.scala b/src/main/scala/Chisel/Data.scala index f9b277e1..0ac3ee32 100644 --- a/src/main/scala/Chisel/Data.scala +++ b/src/main/scala/Chisel/Data.scala @@ -4,7 +4,7 @@ package Chisel import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ sealed abstract class Direction(name: String) { override def toString: String = name @@ -104,13 +104,22 @@ abstract class Data(dirArg: Direction) extends HasId { } object Wire { - def apply[T <: Data](t: T = null, init: T = null): T = { + def apply[T <: Data](t: T): T = + makeWire(t, null.asInstanceOf[T]) + + def apply[T <: Data](dummy: Int = 0, init: T): T = + makeWire(null.asInstanceOf[T], init) + + def apply[T <: Data](t: T, init: T): T = + makeWire(t, init) + + private def makeWire[T <: Data](t: T, init: T): T = { val x = Reg.makeType(t, null.asInstanceOf[T], init) pushCommand(DefWire(x)) if (init != null) { x := init } else { - x.flatten.foreach(e => e := e.fromInt(0)) + pushCommand(DefInvalid(x.ref)) } x } @@ -123,7 +132,7 @@ object Clock { // TODO: Document this. sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { def cloneType: this.type = Clock(dirArg).asInstanceOf[this.type] - private[Chisel] override def flatten: IndexedSeq[UInt] = IndexedSeq() + private[Chisel] override def flatten: IndexedSeq[Bits] = IndexedSeq() private[Chisel] def cloneTypeWidth(width: Width): this.type = cloneType private[Chisel] def toType = "Clock" @@ -132,11 +141,3 @@ sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { case _ => this badConnect that } } - -// TODO: check with FIRRTL specs, how much official implementation flexibility -// is there? -/** A source of garbage data, used to initialize Wires to a don't-care value. */ -private object Poison extends Command { - def apply[T <: Data](t: T): T = - pushCommand(DefPoison(t.cloneType)).id -} diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala index cd88c302..6a5e2095 100644 --- a/src/main/scala/Chisel/Driver.scala +++ b/src/main/scala/Chisel/Driver.scala @@ -6,7 +6,7 @@ import scala.sys.process._ import java.io._ import internal._ -import firrtl._ +import internal.firrtl._ trait BackendCompilationUtilities { /** Create a temporary directory with the prefix name. Exists here because it doesn't in Java 6. diff --git a/src/main/scala/Chisel/Main.scala b/src/main/scala/Chisel/Main.scala new file mode 100644 index 00000000..23abc763 --- /dev/null +++ b/src/main/scala/Chisel/Main.scala @@ -0,0 +1,8 @@ +// See LICENSE for details + +package Chisel + +@deprecated("chiselMain doesn't exist in Chisel3", "3.0") object chiselMain { + def apply[T <: Module](args: Array[String], gen: () => T) = + Predef.assert(false) +} diff --git a/src/main/scala/Chisel/Mem.scala b/src/main/scala/Chisel/Mem.scala index bd27a9c7..21284607 100644 --- a/src/main/scala/Chisel/Mem.scala +++ b/src/main/scala/Chisel/Mem.scala @@ -4,7 +4,7 @@ package Chisel import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") @@ -18,7 +18,7 @@ object Mem { def apply[T <: Data](size: Int, t: T): Mem[T] = { val mt = t.cloneType val mem = new Mem(mt, size) - pushCommand(DefMemory(mem, mt, size, Node(mt._parent.get.clock))) // TODO multi-clock + pushCommand(DefMemory(mem, mt, size)) // TODO multi-clock mem } } @@ -31,20 +31,24 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi */ def apply(idx: Int): T = apply(UInt(idx)) + /** Creates a read/write accessor into the memory with dynamic addressing. + * See the class documentation of the memory for more detailed information. + */ + def apply(idx: UInt): T = makePort(idx, MemPortDirection.INFER) + /** Creates a read accessor into the memory with dynamic addressing. See the * class documentation of the memory for more detailed information. */ - def apply(idx: UInt): T = - pushCommand(DefAccessor(t.cloneType, Node(this), NO_DIR, idx.ref)).id - - def read(idx: UInt): T = apply(idx) + def read(idx: UInt): T = makePort(idx, MemPortDirection.READ) /** Creates a write accessor into the memory. * * @param idx memory element index to write into * @param data new data to write */ - def write(idx: UInt, data: T): Unit = apply(idx) := data + def write(idx: UInt, data: T): Unit = { + makePort(idx, MemPortDirection.WRITE) := data + } /** Creates a masked write accessor into the memory. * @@ -56,12 +60,18 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @note this is only allowed if the memory's element data type is a Vec */ def write(idx: UInt, data: T, mask: Vec[Bool]) (implicit evidence: T <:< Vec[_]): Unit = { - // REVIEW TODO: error checking to detect zip length mismatch? - - val accessor = apply(idx).asInstanceOf[Vec[Data]] - for (((cond, port), datum) <- mask zip accessor zip data.asInstanceOf[Vec[Data]]) + val accessor = makePort(idx, MemPortDirection.WRITE).asInstanceOf[Vec[Data]] + val dataVec = data.asInstanceOf[Vec[Data]] + if (accessor.length != dataVec.length) + Builder.error(s"Mem write data must contain ${accessor.length} elements (found ${dataVec.length})") + if (accessor.length != mask.length) + Builder.error(s"Mem write mask must contain ${accessor.length} elements (found ${mask.length})") + for (((cond, port), datum) <- mask zip accessor zip dataVec) when (cond) { port := datum } } + + private def makePort(idx: UInt, dir: MemPortDirection): T = + pushCommand(DefMemPort(t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock))).id } /** A combinational-read, sequential-write memory. @@ -87,7 +97,7 @@ object SeqMem { def apply[T <: Data](size: Int, t: T): SeqMem[T] = { val mt = t.cloneType val mem = new SeqMem(mt, size) - pushCommand(DefSeqMemory(mem, mt, size, Node(mt._parent.get.clock))) // TODO multi-clock + pushCommand(DefSeqMemory(mem, mt, size)) // TODO multi-clock mem } } @@ -103,6 +113,9 @@ object SeqMem { * result is undefined (unlike Vec, where the last assignment wins) */ sealed class SeqMem[T <: Data](t: T, n: Int) extends MemBase[T](t, n) { - def read(addr: UInt, enable: Bool): T = - read(Mux(enable, addr, Poison(addr))) + def read(addr: UInt, enable: Bool): T = { + val a = Wire(UInt()) + when (enable) { a := addr } + read(a) + } } diff --git a/src/main/scala/Chisel/Module.scala b/src/main/scala/Chisel/Module.scala index 05b7dc26..463c2f81 100644 --- a/src/main/scala/Chisel/Module.scala +++ b/src/main/scala/Chisel/Module.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{ArrayBuffer, HashSet} import internal._ import internal.Builder.pushCommand import internal.Builder.dynamicContext -import firrtl._ +import internal.firrtl._ object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -20,16 +20,12 @@ object Module { def apply[T <: Module](bc: => T): T = { val parent = dynamicContext.currentModule val m = bc.setRefs() - // init module outputs - m._commands prependAll (for (p <- m.io.flatten; if p.dir == OUTPUT) - yield Connect(p.lref, p.fromInt(0).ref)) + m._commands.prepend(DefInvalid(m.io.ref)) // init module outputs dynamicContext.currentModule = parent val ports = m.computePorts Builder.components += Component(m, m.name, ports, m._commands) pushCommand(DefInstance(m, ports)) - // init instance inputs - for (p <- m.io.flatten; if p.dir == INPUT) - p := p.fromInt(0) + pushCommand(DefInvalid(m.io.ref)) // init instance inputs m.connectImplicitIOs() } } @@ -60,7 +56,7 @@ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends HasId { private[Chisel] def ref = Builder.globalRefMap(this) private[Chisel] def lref = ref - private def ports = (clock, "clock") :: (reset, "reset") :: (io, "io") :: Nil + private def ports = (clock, "clk") :: (reset, "reset") :: (io, "io") :: Nil private[Chisel] def computePorts = ports map { case (port, name) => val bundleDir = if (port.isFlip) INPUT else OUTPUT diff --git a/src/main/scala/Chisel/Reg.scala b/src/main/scala/Chisel/Reg.scala index 21415362..e69061c5 100644 --- a/src/main/scala/Chisel/Reg.scala +++ b/src/main/scala/Chisel/Reg.scala @@ -4,7 +4,7 @@ package Chisel import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ object Reg { private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { @@ -45,9 +45,11 @@ object Reg { // to resolve all use cases. If the type inferencer / implicit resolution // system improves, this may be changed. val x = makeType(t, next, init) - pushCommand(DefRegister(x, Node(x._parent.get.clock), Node(x._parent.get.reset))) // TODO multi-clock - if (init != null) { - pushCommand(ConnectInit(x.lref, init.ref)) + val clock = Node(x._parent.get.clock) // TODO multi-clock + if (init == null) { + pushCommand(DefReg(x, clock)) + } else { + pushCommand(DefRegInit(x, clock, Node(x._parent.get.reset), init.ref)) } if (next != null) { x := next diff --git a/src/main/scala/Chisel/When.scala b/src/main/scala/Chisel/When.scala index 7b8d60c2..5f6b02c5 100644 --- a/src/main/scala/Chisel/When.scala +++ b/src/main/scala/Chisel/When.scala @@ -4,7 +4,7 @@ package Chisel import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ object when { // scalastyle:ignore object.name /** Create a `when` condition block, where whether a block of logic is @@ -24,32 +24,33 @@ object when { // scalastyle:ignore object.name * } * }}} */ - def apply(cond: => Bool)(block: => Unit): WhenContext = { - new WhenContext(cond)(block) + def apply(cond: Bool)(block: => Unit): WhenContext = { + new WhenContext(cond, !cond)(block) } } -class WhenContext(cond: => Bool)(block: => Unit) { +/** Internal mechanism for generating a when. Because of the way FIRRTL + * commands are emitted, generating a FIRRTL elsewhen or nested whens inside + * elses would be difficult. Instead, this keeps track of the negative of the + * previous conditions, so when an elsewhen or otherwise is used, it checks + * that both the condition is true and all the previous conditions have been + * false. + */ +class WhenContext(cond: Bool, prevCond: => Bool)(block: => Unit) { /** This block of logic gets executed if above conditions have been false * and this condition is true. */ - def elsewhen (cond: => Bool)(block: => Unit): WhenContext = - doOtherwise(when(cond)(block)) + def elsewhen (elseCond: Bool)(block: => Unit): WhenContext = { + new WhenContext(prevCond && elseCond, prevCond && !elseCond)(block) + } /** This block of logic gets executed only if the above conditions were all * false. No additional logic blocks may be appended past the `otherwise`. */ def otherwise(block: => Unit): Unit = - doOtherwise(block) + new WhenContext(prevCond, null)(block) pushCommand(WhenBegin(cond.ref)) block pushCommand(WhenEnd()) - - private def doOtherwise[T](block: => T): T = { - pushCommand(WhenElse()) - val res = block - pushCommand(WhenEnd()) - res - } } diff --git a/src/main/scala/Chisel/internal/Builder.scala b/src/main/scala/Chisel/internal/Builder.scala index 385e25a2..7e72b5e1 100644 --- a/src/main/scala/Chisel/internal/Builder.scala +++ b/src/main/scala/Chisel/internal/Builder.scala @@ -6,7 +6,7 @@ import scala.util.DynamicVariable import scala.collection.mutable.{ArrayBuffer, HashMap} import Chisel._ -import Chisel.firrtl._ +import Chisel.internal.firrtl._ private[Chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { private var i = 0L @@ -50,7 +50,8 @@ private[Chisel] trait HasId { private[Chisel] def setRef(imm: Arg) = _refMap.setRef(this, imm) private[Chisel] def setRef(name: String) = _refMap.setRef(this, name) private[Chisel] def setRef(parent: HasId, name: String) = _refMap.setField(parent, this, name) - private[Chisel] def setRef(parent: HasId, index: Int) = _refMap.setIndex(parent, this, index) + private[Chisel] def setRef(parent: HasId, index: Int) = _refMap.setIndex(parent, this, ILit(index)) + private[Chisel] def setRef(parent: HasId, index: UInt) = _refMap.setIndex(parent, this, index.ref) private[Chisel] def getRef = _refMap(this) } @@ -66,7 +67,7 @@ class RefMap { private[Chisel] def setField(parentid: HasId, id: HasId, name: String): Unit = _refmap(id._id) = Slot(Node(parentid), name) - private[Chisel] def setIndex(parentid: HasId, id: HasId, index: Int): Unit = + private[Chisel] def setIndex(parentid: HasId, id: HasId, index: Arg): Unit = _refmap(id._id) = Index(Node(parentid), index) def apply(id: HasId): Arg = _refmap(id._id) diff --git a/src/main/scala/Chisel/firrtl/Emitter.scala b/src/main/scala/Chisel/internal/firrtl/Emitter.scala index 1d0f4ddc..13d9fa8f 100644 --- a/src/main/scala/Chisel/firrtl/Emitter.scala +++ b/src/main/scala/Chisel/internal/firrtl/Emitter.scala @@ -1,6 +1,6 @@ // See LICENSE for license details. -package Chisel.firrtl +package Chisel.internal.firrtl import Chisel._ private class Emitter(circuit: Circuit) { @@ -11,16 +11,16 @@ private class Emitter(circuit: Circuit) { private def emit(e: Command, ctx: Component): String = e match { case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).reduce(_ + ", " + _)})" case e: DefWire => s"wire ${e.name} : ${e.id.toType}" - case e: DefPoison[_] => s"poison ${e.name} : ${e.id.toType}" - case e: DefRegister => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}, ${e.reset.fullName(ctx)}" - case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}], ${e.clock.fullName(ctx)}" - case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}], ${e.clock.fullName(ctx)}" - case e: DefAccessor[_] => s"infer accessor ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}]" - case e: Connect => s"${e.loc.fullName(ctx)} := ${e.exp.fullName(ctx)}" - case e: BulkConnect => s"${e.loc1.fullName(ctx)} <> ${e.loc2.fullName(ctx)}" - case e: ConnectInit => s"onreset ${e.loc.fullName(ctx)} := ${e.exp.fullName(ctx)}" - case e: Stop => s"stop(${e.clk.fullName(ctx)}, ${e.ret})" - case e: Printf => s"""printf(${e.clk.fullName(ctx)}, "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" + case e: DefReg => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}" + case e: DefRegInit => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))" + case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}]" + case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}]" + case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}" + case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}" + case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}" + case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})" + case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" + case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid" case e: DefInstance => { val modName = moduleMap.getOrElse(e.id.name, e.id.name) s"inst ${e.name} of $modName" @@ -29,9 +29,6 @@ private class Emitter(circuit: Circuit) { case w: WhenBegin => indent() s"when ${w.pred.fullName(ctx)} :" - case _: WhenElse => - indent() - "else :" case _: WhenEnd => unindent() "skip" diff --git a/src/main/scala/Chisel/firrtl/IR.scala b/src/main/scala/Chisel/internal/firrtl/IR.scala index 8cc31b54..7bb273c0 100644 --- a/src/main/scala/Chisel/firrtl/IR.scala +++ b/src/main/scala/Chisel/internal/firrtl/IR.scala @@ -1,6 +1,6 @@ // See LICENSE for license details. -package Chisel.firrtl +package Chisel.internal.firrtl import Chisel._ import Chisel.internal._ @@ -10,12 +10,12 @@ case class PrimOp(val name: String) { object PrimOp { val AddOp = PrimOp("add") - val AddModOp = PrimOp("addw") val SubOp = PrimOp("sub") - val SubModOp = PrimOp("subw") + val TailOp = PrimOp("tail") + val HeadOp = PrimOp("head") val TimesOp = PrimOp("mul") val DivideOp = PrimOp("div") - val ModOp = PrimOp("mod") + val RemOp = PrimOp("rem") val ShiftLeftOp = PrimOp("shl") val ShiftRightOp = PrimOp("shr") val DynamicShiftLeftOp = PrimOp("dshl") @@ -25,7 +25,6 @@ object PrimOp { val BitXorOp = PrimOp("xor") val BitNotOp = PrimOp("not") val ConcatOp = PrimOp("cat") - val BitSelectOp = PrimOp("bit") val BitsExtractOp = PrimOp("bits") val LessOp = PrimOp("lt") val LessEqOp = PrimOp("leq") @@ -90,9 +89,9 @@ case class Slot(imm: Node, name: String) extends Arg { override def fullName(ctx: Component): String = if (imm.fullName(ctx).isEmpty) name else s"${imm.fullName(ctx)}.${name}" } -case class Index(imm: Arg, value: Int) extends Arg { +case class Index(imm: Arg, value: Arg) extends Arg { def name: String = s"[$value]" - override def fullName(ctx: Component): String = s"${imm.fullName(ctx)}[$value]" + override def fullName(ctx: Component): String = s"${imm.fullName(ctx)}[${value.fullName(ctx)}]" } object Width { @@ -132,21 +131,31 @@ sealed case class KnownWidth(value: Int) extends Width { override def toString: String = value.toString } +sealed abstract class MemPortDirection(name: String) { + override def toString: String = name +} +object MemPortDirection { + object READ extends MemPortDirection("read") + object WRITE extends MemPortDirection("write") + object RDWR extends MemPortDirection("rdwr") + object INFER extends MemPortDirection("infer") +} + abstract class Command abstract class Definition extends Command { def id: HasId def name: String = id.getRef.name } case class DefPrim[T <: Data](id: T, op: PrimOp, args: Arg*) extends Definition +case class DefInvalid(arg: Arg) extends Command case class DefWire(id: Data) extends Definition -case class DefRegister(id: Data, clock: Arg, reset: Arg) extends Definition -case class DefMemory(id: HasId, t: Data, size: Int, clock: Arg) extends Definition -case class DefSeqMemory(id: HasId, t: Data, size: Int, clock: Arg) extends Definition -case class DefAccessor[T <: Data](id: T, source: Node, direction: Direction, index: Arg) extends Definition +case class DefReg(id: Data, clock: Arg) extends Definition +case class DefRegInit(id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +case class DefMemory(id: HasId, t: Data, size: Int) extends Definition +case class DefSeqMemory(id: HasId, t: Data, size: Int) extends Definition +case class DefMemPort[T <: Data](id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition case class DefInstance(id: Module, ports: Seq[Port]) extends Definition -case class DefPoison[T <: Data](id: T) extends Definition case class WhenBegin(pred: Arg) extends Command -case class WhenElse() extends Command case class WhenEnd() extends Command case class Connect(loc: Node, exp: Arg) extends Command case class BulkConnect(loc1: Node, loc2: Node) extends Command diff --git a/src/main/scala/Chisel/testers/BasicTester.scala b/src/main/scala/Chisel/testers/BasicTester.scala index 1079727c..6807a30e 100644 --- a/src/main/scala/Chisel/testers/BasicTester.scala +++ b/src/main/scala/Chisel/testers/BasicTester.scala @@ -5,7 +5,7 @@ import Chisel._ import internal._ import internal.Builder.pushCommand -import firrtl._ +import internal.firrtl._ class BasicTester extends Module { // The testbench has no IOs, rather it should communicate using printf, assert, and stop. diff --git a/src/main/scala/Chisel/util/Arbiter.scala b/src/main/scala/Chisel/util/Arbiter.scala index 119b9f5a..2747640f 100644 --- a/src/main/scala/Chisel/util/Arbiter.scala +++ b/src/main/scala/Chisel/util/Arbiter.scala @@ -7,7 +7,7 @@ package Chisel /** An I/O bundle for the Arbiter */ class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle { - val in = Vec(Decoupled(gen), n).flip + val in = Vec(n, Decoupled(gen)).flip val out = Decoupled(gen) val chosen = UInt(OUTPUT, log2Up(n)) } diff --git a/src/main/scala/Chisel/util/Decoupled.scala b/src/main/scala/Chisel/util/Decoupled.scala index b1505887..ca000af9 100644 --- a/src/main/scala/Chisel/util/Decoupled.scala +++ b/src/main/scala/Chisel/util/Decoupled.scala @@ -82,7 +82,7 @@ class Queue[T <: Data](gen: T, val entries: Int, { val io = new QueueIO(gen, entries) - val ram = Mem(gen, entries) + val ram = Mem(entries, gen) val enq_ptr = Counter(entries) val deq_ptr = Counter(entries) val maybe_full = Reg(init=Bool(false)) diff --git a/src/test/scala/chiselTests/When.scala b/src/test/scala/chiselTests/When.scala new file mode 100644 index 00000000..b78e1c5a --- /dev/null +++ b/src/test/scala/chiselTests/When.scala @@ -0,0 +1,60 @@ +// See LICENSE for license details. + +package chiselTests + +import org.scalatest._ +import Chisel._ +import Chisel.testers.BasicTester + +class WhenTester() extends BasicTester { + val cnt = Counter(4) + when(Bool(true)) { cnt.inc() } + + val out = Wire(UInt(width=3)) + when(cnt.value === UInt(0)) { + out := UInt(1) + } .elsewhen (cnt.value === UInt(1)) { + out := UInt(2) + } .elsewhen (cnt.value === UInt(2)) { + out := UInt(3) + } .otherwise { + out := UInt(0) + } + + assert(out === cnt.value + UInt(1)) + + when(cnt.value === UInt(3)) { + stop() + } +} + +class OverlappedWhenTester() extends BasicTester { + val cnt = Counter(4) + when(Bool(true)) { cnt.inc() } + + val out = Wire(UInt(width=3)) + when(cnt.value <= UInt(0)) { + out := UInt(1) + } .elsewhen (cnt.value <= UInt(1)) { + out := UInt(2) + } .elsewhen (cnt.value <= UInt(2)) { + out := UInt(3) + } .otherwise { + out := UInt(0) + } + + assert(out === cnt.value + UInt(1)) + + when(cnt.value === UInt(3)) { + stop() + } +} + +class WhenSpec extends ChiselFlatSpec { + "When, elsewhen, and otherwise with orthogonal conditions" should "work" in { + assert(execute{ new WhenTester }) + } + "When, elsewhen, and otherwise with overlapped conditions" should "work" in { + assert(execute{ new OverlappedWhenTester }) + } +} |
