diff options
| -rw-r--r-- | doc/images/vec-forall.svg | 330 | ||||
| -rw-r--r-- | src/main/scala/Chisel/Core.scala | 588 |
2 files changed, 840 insertions, 78 deletions
diff --git a/doc/images/vec-forall.svg b/doc/images/vec-forall.svg new file mode 100644 index 00000000..24c6a267 --- /dev/null +++ b/doc/images/vec-forall.svg @@ -0,0 +1,330 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="80.426331mm" + height="35.299992mm" + viewBox="0 0 284.97519 125.07871" + id="svg8120" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="vec-forall.svg"> + <defs + id="defs8122"> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker11155" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path11157" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="marker11031" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path11033" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(-0.6,-0.6)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker10791" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path10793" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker9859" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path9861" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Mend" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path4528" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(-0.6,-0.6)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Mend-2-5" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + inkscape:connector-curvature="0" + id="path4528-3-9" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(-0.6,-0.6)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker9859-9" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend" + inkscape:collect="always"> + <path + inkscape:connector-curvature="0" + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path9861-3" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="marker11031-8" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path11033-9" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(-0.6,-0.6)" + inkscape:connector-curvature="0" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2" + inkscape:cx="158.34386" + inkscape:cy="229.72315" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:snap-bbox="true" + inkscape:snap-bbox-midpoints="true" + inkscape:snap-midpoints="true" + inkscape:snap-smooth-nodes="true" + inkscape:object-nodes="true" + inkscape:snap-text-baseline="true" + inkscape:window-width="1278" + inkscape:window-height="1550" + inkscape:window-x="2480" + inkscape:window-y="185" + inkscape:window-maximized="0" + fit-margin-top="2.5" + fit-margin-left="2.5" + fit-margin-right="2.5" + fit-margin-bottom="2.5"> + <inkscape:grid + type="xygrid" + id="grid8128" + originx="9.6135842" + originy="0.53150127" /> + </sodipodi:namedview> + <metadata + id="metadata8125"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(9.6135842,-927.81499)"> + <g + id="g8676" + transform="translate(-7.0760988e-6,26.574814)"> + <rect + y="910.62994" + x="35.433071" + height="17.716536" + width="70.866142" + id="rect8130" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text8672" + y="923.27478" + x="54.53466" + style="font-style:normal;font-weight:normal;font-size:18.75px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-size:13.75px" + y="923.27478" + x="54.53466" + id="tspan8674" + sodipodi:role="line">p(...)</tspan></text> + </g> + <g + id="g8681" + transform="translate(-7.0760988e-6,62.007885)"> + <rect + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect8683" + width="70.866142" + height="17.716536" + x="35.433071" + y="910.62994" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:18.75px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="54.53466" + y="923.27478" + id="text8685" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan8687" + x="54.53466" + y="923.27478" + style="font-size:13.75px">p(...)</tspan></text> + </g> + <g + transform="translate(-6.8057659e-6,115.15748)" + id="g8689"> + <rect + y="910.62994" + x="35.433071" + height="17.716536" + width="70.866142" + id="rect8691" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text8693" + y="923.27478" + x="54.53466" + style="font-style:normal;font-weight:normal;font-size:18.75px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="font-size:13.75px" + y="923.27478" + x="54.53466" + id="tspan8695" + sodipodi:role="line">p(...)</tspan></text> + </g> + <circle + style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path8705" + cx="70.866135" + cy="999.21265" + r="2.2145669" /> + <circle + r="2.2145669" + cy="1008.0709" + cx="70.866135" + id="circle8707" + style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <circle + style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.0629921;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="circle8709" + cx="70.866135" + cy="1016.9291" + r="2.2145669" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)" + d="m -6.535433e-6,981.49609 35.433070535433,0" + id="path8711" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10791)" + d="m -0.75533063,946.07262 35.43307063,0" + id="path8711-9" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend-2-5)" + d="m -0.75533068,1034.6553 35.43307068,0" + id="path8711-9-4" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path9853" + d="m 107.05453,981.48649 34.67774,0.01" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker9859)" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 141.73229,946.063 0,88.5827 35.43307,0 c 26.57481,0 53.14961,-17.7165 53.14961,-44.29135 0,-26.5748 -26.5748,-44.29135 -53.14961,-44.29135 z" + id="path10133" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path9853-3" + d="m 230.31497,990.35435 34.67774,0.01" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker9859-9)" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.06299222;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11031)" + d="m 106.2992,946.063 c 17.71654,0 17.71654,0 17.71654,0 l 0,17.71653 17.71653,0" + id="path11023" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.06299222;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11031-8)" + d="m 106.29921,1034.6457 c 17.71654,0 17.71654,0 17.71654,0 l 0,-17.7165 17.71653,0" + id="path11023-6" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/src/main/scala/Chisel/Core.scala b/src/main/scala/Chisel/Core.scala index 9ec6f24d..217a5a72 100644 --- a/src/main/scala/Chisel/Core.scala +++ b/src/main/scala/Chisel/Core.scala @@ -14,17 +14,17 @@ object INPUT extends Direction("input") { def flip = OUTPUT } object OUTPUT extends Direction("output") { def flip = INPUT } object NO_DIR extends Direction("?") { def flip = NO_DIR } +// REVIEW TODO: Should this actually be part of the RTL API? RTL should be +// considered untouchable from a debugging standpoint? object debug { // TODO: def apply (arg: Data) = arg } -/** *Data* is the root of the type system which includes - Aggregate (Bundle, Vec) and Element (UInt, SInt, etc.). - - Instances of Data are meant to help with construction and correctness - of a logic graph. They will trimmed out of the graph before a *Backend* - generates target code. +/** This forms the root of the type system for wire data types. The data value + * must be representable as some number (need not be known at Chisel compile + * time) of bits, and must have methods to pack / unpack structured data to / + * from bits. */ abstract class Data(dirArg: Direction) extends HasId { def dir: Direction = dirVar @@ -57,6 +57,9 @@ abstract class Data(dirArg: Direction) extends HasId { private[Chisel] def cloneTypeWidth(width: Width): this.type private[Chisel] def toType: String + // REVIEW TODO: Can these just be abstract, and left to implementing classes + // to define them (or even undefined)? Bonus: compiler can help you catch + // unimplemented functions. def := (that: Data): Unit = this badConnect that def <> (that: Data): Unit = this badConnect that def cloneType: this.type @@ -67,8 +70,24 @@ abstract class Data(dirArg: Direction) extends HasId { def width: Width final def getWidth = width.get + // REVIEW TODO: should this actually be part of the Data interface? this is + // an Aggregate function? private[Chisel] def flatten: IndexedSeq[Bits] + + /** Creates an new instance of this type, unpacking the input Bits into + * structured data. Generates no logic (should be either wires or a syntactic + * transformation). + * + * This performs the inverse operation of toBits. + * + * @note does NOT assign to the object this is called on, instead creating a + * NEW object + */ def fromBits(n: Bits): this.type = { + // REVIEW TODO: width match checking? + // REVIEW TODO: perhaps have a assign version, especially since this is + // called from a specific object, instead of a factory constructor. It's + // not immediately obvious that this creates a new object. var i = 0 val wire = Wire(this.cloneType) for (x <- wire.flatten) { @@ -77,6 +96,12 @@ abstract class Data(dirArg: Direction) extends HasId { } wire.asInstanceOf[this.type] } + + /** Packs the value of this object as plain Bits. Generates no logic (should + * be either wires or a syntactic transformation). + * + * This performs the inverse operation of fromBits(Bits). + */ def toBits(): UInt = Cat(this.flatten.reverse) } @@ -92,7 +117,6 @@ object Wire { } } -/** A factory for Reg objects. */ object Reg { private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) t.cloneType @@ -104,7 +128,17 @@ object Reg { } else throwException("cannot infer type") } + /** Creates a register with optional next and initialization values. + * + * @param t: data type for the register + * @param next: new value register is to be updated with every cycle (or + * empty to not update unless assigned to using the := operator) + * @param init: initialization value on reset (or empty for uninitialized, + * where the register value persists across a reset) + */ def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = { + // REVIEW TODO: rewrite this in a less brittle way, perhaps also in a way + // that doesn't need two implementations of apply() 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) @@ -113,6 +147,12 @@ object Reg { x := next x } + + /** Creates a register without initialization (reset is ignored). Value does + * not change unless assigned to (using the := operator). + * + * @param outType: data type for the register + */ def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T]) } @@ -120,6 +160,11 @@ object Mem { @deprecated("Chisel3 Mem argument order should be size, t - this will be removed by Chisel3 official release", "now") def apply[T <: Data](t: T, size: Int): Mem[T] = apply(size, t) + /** Creates a combinational-read, sequential-write [[Mem]]. + * + * @param size number of elements in the memory + * @param t data type of memory element + */ def apply[T <: Data](size: Int, t: T): Mem[T] = { val mt = t.cloneType val mem = new Mem(mt, size) @@ -129,25 +174,63 @@ object Mem { } sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId with VecLike[T] { + // REVIEW TODO: make accessors (static/dynamic, read/write) combinations consistent. + + /** Creates a read accessor into the memory with static addressing. See the + * class documentation of the memory for more detailed information. + */ def apply(idx: Int): T = apply(UInt(idx)) + + /** 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) + + /** 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 + + /** Creates a masked write accessor into the memory. + * + * @param idx memory element index to write into + * @param data new data to write + * @param mask write mask as a Vec of Bool: a write to the Vec element in + * memory is only performed if the corresponding mask index is true. + * + * @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]]) when (cond) { port := datum } } } +/** A combinational-read, sequential-write memory. + * + * Writes take effect on the rising clock edge after the request. Reads are + * combinational (requests will return data on the same cycle). + * Read-after-write hazards are not an issue. + */ sealed class Mem[T <: Data](t: T, length: Int) extends MemBase(t, length) object SeqMem { @deprecated("Chisel3 SeqMem argument order should be size, t - this will be removed by Chisel3 official release", "now") def apply[T <: Data](t: T, size: Int): SeqMem[T] = apply(size, t) + /** Creates a sequential-read, sequential-write [[SeqMem]]. + * + * @param size number of elements in the memory + * @param t data type of memory element + */ def apply[T <: Data](size: Int, t: T): SeqMem[T] = { val mt = t.cloneType val mem = new SeqMem(mt, size) @@ -156,19 +239,39 @@ object SeqMem { } } +/** A sequential-read, sequential-write memory. + * + * Writes take effect on the rising clock edge after the request. Reads return + * data on the rising edge after the request. Read-after-write behavior (when + * a read and write to the same address are requested on the same cycle) is + * undefined. + */ 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))) } object Vec { + /** Creates a new [[Vec]] with `n` entries of the specified data type. + * + * @note elements are NOT assigned by default and have no value + */ def apply[T <: Data](n: Int, gen: T): Vec[T] = new Vec(gen.cloneType, n) @deprecated("Chisel3 vec argument order should be n, gen - this will be removed by Chisel3 official release", "now") def apply[T <: Data](gen: T, n: Int): Vec[T] = new Vec(gen.cloneType, n) - /** Returns a new *Vec* from a sequence of *Data* nodes. + + /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]] + * nodes. + * + * @note input elements should be of the same type + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements */ def apply[T <: Data](elts: Seq[T]): Vec[T] = { + // REVIEW TODO: error checking to guard against type mismatch? + require(!elts.isEmpty) val width = elts.map(_.width).reduce(_ max _) val vec = new Vec(elts.head.cloneTypeWidth(width), elts.length) @@ -177,31 +280,57 @@ object Vec { v := e vec } - /** Returns a new *Vec* from the concatenation of a *Data* node - and a sequence of *Data* nodes. + + /** Creates a new [[Vec]] composed of the input [[Data]] nodes. + * + * @note input elements should be of the same type + * @note the width of all output elements is the width of the largest input + * element + * @note output elements are connected from the input elements */ def apply[T <: Data](elt0: T, elts: T*): Vec[T] = + // REVIEW TODO: does this really need to exist as a standard function? apply(elt0 +: elts.toSeq) - /** Returns an array containing values of a given function over - a range of integer values starting from 0. + + /** Creates a new [[Vec]] of length `n` composed of the results of the given + * function applied over a range of integer values starting from 0. + * + * @param n number of elements in the vector (the function is applied from + * 0 to `n-1`) + * @param gen function that takes in an Int (the index) and returns a + * [[Data]] that becomes the output element */ - def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = + def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = apply((0 until n).map(i => gen(i))) - /** Returns an array that contains the results of some element computation - a number of times. - Note that this means that elem is computed a total of n times. + /** Creates a new [[Vec]] of length `n` composed of the result of the given + * function repeatedly applied. + * + * @param n number of elements (amd the number of times the function is + * called) + * @param gen function that generates the [[Data]] that becomes the output + * element */ def fill[T <: Data](n: Int)(gen: => T): Vec[T] = apply(Seq.fill(n)(gen)) } +/** An abstract class for data types that solely consist of (are an aggregate + * of) other Data objects. + */ sealed abstract class Aggregate(dirArg: Direction) extends Data(dirArg) { private[Chisel] def cloneTypeWidth(width: Width): this.type = cloneType def width: Width = flatten.map(_.width).reduce(_ + _) } +/** A vector (array) of [[Data]] elements. Provides hardware versions of various + * collection transformation functions found in software array implementations. + * + * @tparam T type of elements + */ sealed class Vec[T <: Data] private (gen: => T, val length: Int) extends Aggregate(gen.dir) with VecLike[T] { + // REVIEW TODO: should this take a Seq instead of a gen()? + private val self = IndexedSeq.fill(length)(gen) override def <> (that: Data): Unit = that match { @@ -210,10 +339,13 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) } def <> (that: Seq[T]): Unit = + // REVIEW TODO: come up with common style: match on type in body or + // multiple invocation signatures for ((a, b) <- this zip that) a <> b def <> (that: Vec[T]): Unit = this bulkConnect that + // REVIEW TODO: standardize as above override def := (that: Data): Unit = that match { case _: Vec[_] => this connect that @@ -221,6 +353,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) } def := (that: Seq[T]): Unit = { + // REVIEW TODO: standardize as above require(this.length == that.length) for ((a, b) <- this zip that) a := b @@ -228,14 +361,25 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) def := (that: Vec[T]): Unit = this connect that + /** Creates a dynamically indexed read accessor into the array. Generates + * logic (likely some kind of multiplexer). + */ def apply(idx: UInt): T = { val x = gen + // REVIEW TODO: what happens when people try to assign into this? + // Should this be a read-only reference? pushCommand(DefAccessor(x, Node(this), NO_DIR, idx.ref)) x } + /** Creates a statically indexed read accessor into the array. Generates no + * logic. + */ def apply(idx: Int): T = self(idx) + def read(idx: UInt): T = apply(idx) + // REVIEW TODO: does this need to exist? + def write(idx: UInt, data: T): Unit = apply(idx) := data override def cloneType: this.type = @@ -250,26 +394,86 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) elt.setRef(this, i) } +/** A trait for [[Vec]]s containing common hardware generators for collection + * operations. + */ trait VecLike[T <: Data] extends collection.IndexedSeq[T] { def read(idx: UInt): T + // REVIEW TODO: does this need to exist? (does the same thing as apply) + def write(idx: UInt, data: T): Unit def apply(idx: UInt): T - def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_&&_) - def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_||_) - def contains(x: T) (implicit evidence: T <:< UInt): Bool = this.exists(_ === x) + /** Outputs true if p outputs true for every element. + * + * This generates into a function evaluation followed by a logical AND + * reduction. + */ + def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_ && _) + + /** Outputs true if p outputs true for at least one element. + * + * This generates into a function evaluation followed by a logical OR + * reduction. + */ + def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_ || _) + + /** Outputs true if the vector contains at least one element equal to x (using + * the === operator). + * + * This generates into an equality comparison followed by a logical OR + * reduction. + */ + def contains(x: T)(implicit evidence: T <:< UInt): Bool = this.exists(_ === x) + + /** Outputs the number of elements for which p is true. + * + * This generates into a function evaluation followed by a set bit counter. + */ def count(p: T => Bool): UInt = PopCount((this map p).toSeq) + /** Helper function that appends an index (literal value) to each element, + * useful for hardware generators which output an index. + */ private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt(i)) + + /** Outputs the index of the first element for which p outputs true. + * + * This generates into a function evaluation followed by a priority mux. + */ def indexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p)) + + /** Outputs the index of the last element for which p outputs true. + * + * This generates into a function evaluation followed by a priority mux. + */ def lastIndexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p).reverse) + + /** Outputs the index of the element for which p outputs true, assuming that + * the there is exactly one such element. + * + * This generates into a function evaluation followed by a one-hot mux. The + * implementation may be more efficient than a priority mux, but incorrect + * results are possible if there is not exactly one true element. + */ def onlyIndexWhere(p: T => Bool): UInt = Mux1H(indexWhereHelper(p)) + // REVIEW TODO: can (should?) this be assertion checked? } -/** A bit pattern object to enable representation of dont cares */ object BitPat { + /** Parses a bit pattern string into (bits, mask, width). + * + * @return bits the literal value, with don't cares being 0 + * @return mask the mask bits, with don't cares being 0 and cares being 1 + * @return width the number of bits in the literal, including values and + * don't cares. + */ private def parse(x: String): (BigInt, BigInt, Int) = { - require(x.head == 'b', "BINARY BitPats ONLY") + // REVIEW TODO: can this be merged with literal parsing creating one unified + // Chisel string to value decoder (which can also be invoked by libraries + // and testbenches? + // REVIEW TODO: Verilog Xs also handle octal and hex cases. + require(x.head == 'b', "BitPats must be in binary and be prefixed with 'b'") var bits = BigInt(0) var mask = BigInt(0) for (d <- x.tail) { @@ -279,50 +483,67 @@ object BitPat { bits = (bits << 1) + (if (d == '1') 1 else 0) } } - (bits, mask, x.length-1) + (bits, mask, x.length - 1) } - /** Get a bit pattern from a string - * @param n a string with format b---- eg) b1?01 - * @note legal characters are 0, 1, ? and must be base 2*/ + /** Creates a [[BitPat]] literal from a string. + * + * @param n the literal value as a string, in binary, prefixed with 'b' + * @note legal characters are '0', '1', and '?', as well as '_' as white + * space (which are ignored) + */ def apply(n: String): BitPat = { val (bits, mask, width) = parse(n) new BitPat(bits, mask, width) } - /** Get a bit pattern of don't cares with a specified width */ + /** Creates a [[BitPat]] of all don't cares of a specified width. */ + // REVIEW TODO: is this really necessary? if so, can there be a better name? def DC(width: Int): BitPat = BitPat("b" + ("?" * width)) // BitPat <-> UInt /** enable conversion of a bit pattern to a UInt */ + // REVIEW TODO: Doesn't having a BitPat with all mask bits high defeat the + // point of using a BitPat in the first place? implicit def BitPatToUInt(x: BitPat): UInt = { - require(x.mask == (BigInt(1) << x.getWidth)-1) + require(x.mask == (BigInt(1) << x.getWidth) - 1) UInt(x.value, x.getWidth) } + /** create a bit pattern from a UInt */ + // REVIEW TODO: Similar, what is the point of this? implicit def apply(x: UInt): BitPat = { require(x.isLit) BitPat("b" + x.litValue.toString(2)) } } -/** A class to create bit patterns - * Use the [[Chisel.BitPat$ BitPat]] object instead of this class directly */ +// TODO: Break out of Core? (this doesn't involve FIRRTL generation) +/** Bit patterns are literals with masks, used to represent values with don't + * cares. Equality comparisons will ignore don't care bits (for example, + * BitPat(0b10?1) === UInt(0b1001) and UInt(0b1011)). + */ 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) } +/** 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) { + // REVIEW TODO: toBits is implemented in terms of flatten... inheriting this + // without rewriting toBits will break things. Perhaps have a specific element + // API? private[Chisel] def flatten: IndexedSeq[UInt] = IndexedSeq(toBits) } -/** Create a new Clock */ object Clock { def apply(dir: Direction = NO_DIR): Clock = new Clock(dir) } +// 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() @@ -335,35 +556,62 @@ sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { } } +/** A data type for values represented by a single bitvector. Provides basic + * bitwise operations. + */ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: Option[LitArg]) extends Element(dirArg, width) { + // REVIEW TODO: should this be abstract? It may be good to use Bits for values + // where you don't need artihmetic operations / arithmetic doesn't make sense + // like opcodes and stuff. + + // REVIEW TODO: Why do we need a fromInt? Why does it drop the argument? def fromInt(x: BigInt): this.type + // REVIEW TODO: purpose of dedicated lit logic? def makeLit(value: BigInt): LitArg def cloneType: this.type = cloneTypeWidth(width) override def <> (that: Data): Unit = this := that - /** Extract a single Bool at index *bit*. + /** Returns the specified bit on this wire as a [[Bool]], statically + * addressed. Generates no logic. */ + // REVIEW TODO: Ddeduplicate constructor with apply(Int) final def apply(x: BigInt): Bool = { if (x < 0) Builder.error(s"Negative bit indices are illegal (got $x)") if (isLit()) Bool(((litValue() >> x.toInt) & 1) == 1) else pushOp(DefPrim(Bool(), BitSelectOp, this.ref, ILit(x))) } + final def apply(x: Int): Bool = apply(BigInt(x)) + + /** Returns the specified bit on this wire as a [[Bool]], dynamically + * addressed. Generates logic: implemented as a variable shifter. + */ final def apply(x: UInt): Bool = (this >> x)(0) - /** Extract a range of bits, inclusive from hi to lo - * {{{ myBits = 0x5, myBits(1,0) => 0x1 }}} */ + /** Returns a subset of bits on this wire from `hi` to `lo` (inclusive), + * statically addressed. Generates no logic. + * + * @example + * {{{ + * myBits = 0x5 = 0b101 + * myBits(1,0) => 0b01 // extracts the two least significant bits + * }}} + */ final def apply(x: Int, y: Int): UInt = { if (x < y || y < 0) Builder.error(s"Invalid bit range ($x,$y)") + // REVIEW TODO: should we support negative indexing Python style, at least + // where widths are known? val w = x - y + 1 if (isLit()) UInt((litValue >> y) & ((BigInt(1) << w) - 1), w) else pushOp(DefPrim(UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y))) } + + // REVIEW TODO: again, is this necessary? Or just have this and use implicits? final def apply(x: BigInt, y: BigInt): UInt = apply(x.toInt, y.toInt) private[Chisel] def unop[T <: Data](dest: T, op: PrimOp): T = @@ -377,22 +625,63 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: private[Chisel] def redop(op: PrimOp): Bool = pushOp(DefPrim(Bool(), op, this.ref)) - /** invert all bits with ~ */ + /** 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 + */ def pad (other: Int): this.type = binop(cloneTypeWidth(this.width max Width(other)), PadOp, other) /** Shift left operation */ + // REVIEW TODO: redundant + // REVIEW TODO: should these return this.type or Bits? def << (other: BigInt): Bits + + /** Returns this wire statically left shifted by the specified amount, + * inserting zeros into the least significant bits. + * + * The width of the output is `other` larger than the input. Generates no + * logic. + */ def << (other: Int): Bits + + /** Returns this wire dynamically left shifted by the specified amount, + * inserting zeros into the least significant bits. + * + * The width of the output is `pow(2, width(other))` larger than the input. + * Generates a dynamic shifter. + */ def << (other: UInt): Bits + /** Shift right operation */ + // REVIEW TODO: redundant def >> (other: BigInt): Bits + + /** Returns this wire statically right shifted by the specified amount, + * inserting zeros into the most significant bits. + * + * The width of the output is the same as the input. Generates no logic. + */ def >> (other: Int): Bits + + /** Returns this wire dynamically right shifted by the specified amount, + * inserting zeros into the most significant bits. + * + * The width of the output is the same as the input. Generates a dynamic + * shifter. + */ def >> (other: UInt): Bits - /** Split up this bits instantiation to a Vec of Bools */ + /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s. Generates no + * logic. + */ def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i)) + // REVIEW TODO: is this appropriate here? Should this be a (implicit?) cast in + // the SInt object instead? Bits shouldn't know about UInt/SInt, which are + // downstream? def asSInt(): SInt def asUInt(): UInt final def toSInt(): SInt = asSInt @@ -403,9 +692,17 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: case _ => throwException(s"can't covert UInt<$width> to Bool") } - /** Cat bits together to into a single data object with the width of both combined */ + // REVIEW TODO: where did this syntax come from? + /** Returns this wire concatenated with `other`, where this wire forms the + * most significant part and `other` forms the least significant part. + * + * The width of the output is sum of the inputs. Generates no logic. + */ def ## (other: Bits): UInt = Cat(this, other) + + // REVIEW TODO: This just _looks_ wrong. override def toBits = asUInt + override def fromBits(n: Bits): this.type = { val res = Wire(this).asInstanceOf[this.type] res := n @@ -413,24 +710,75 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: } } +// REVIEW TODO: Numeric (strictly UInt/SInt/float) or numeric-like (complex, +// etc)? First is easy to define, second not so much. Perhaps rename IntLike? +// Also should add intended purpose. +/** Abstract trait defining operations available on numeric-like wire data + * types. + */ abstract trait Num[T <: Data] { // def << (b: T): T; // def >> (b: T): T; //def unary_-(): T; + + // REVIEW TODO: double check ops conventions against FIRRTL + + /** Outputs the sum of `this` and `b`. The resulting width is the max of the + * operands plus 1 (should not overflow). + */ def + (b: T): T; + + /** Outputs the product of `this` and `b`. The resulting width is the sum of + * the operands. + * + * @note can generate a single-cycle multiplier, which can result in + * significant cycle time and area costs + */ def * (b: T): T; + + /** Outputs the quotient of `this` and `b`. + * + * TODO: full rules + */ def / (b: T): T; + def % (b: T): T; + + /** Outputs the difference of `this` and `b`. The resulting width is the max + * of the operands plus 1 (should not overflow). + */ def - (b: T): T; + + /** Outputs true if `this` < `b`. + */ def < (b: T): Bool; + + /** Outputs true if `this` <= `b`. + */ def <= (b: T): Bool; + + /** Outputs true if `this` > `b`. + */ def > (b: T): Bool; + + /** Outputs true if `this` >= `b`. + */ def >= (b: T): Bool; + /** Outputs the minimum of `this` and `b`. The resulting width is the max of + * the operands. Generates a comparison followed by a mux. + */ def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b) + + /** Outputs the maximum of `this` and `b`. The resulting width is the max of + * the operands. Generates a comparison followed by a mux. + */ def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T]) } +/** A data type for unsigned integers, represented as a binary bitvector. + * Defines arithmetic operations between other integer types. + */ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULit] = None) extends Bits(dir, width, lit) with Num[UInt] { private[Chisel] override def cloneTypeWidth(w: Width): this.type = new UInt(dir, w).asInstanceOf[this.type] @@ -444,6 +792,7 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi case _ => this badConnect that } + // TODO: refactor to share documentation with Num or add independent scaladoc def unary_- = UInt(0) - this def unary_-% = UInt(0) -% this def +& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), AddOp, other) @@ -461,6 +810,7 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi 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) + // REVIEW TODO: Can this be defined on Bits? def orR = this != UInt(0) def andR = ~this === UInt(0) def xorR = redop(XorReduceOp) @@ -473,6 +823,7 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi def === (other: UInt): Bool = compop(EqualOp, other) def unary_! : Bool = this === Bits(0) + // REVIEW TODO: Can these also not be defined on Bits? def << (other: Int): UInt = binop(UInt(this.width + other), ShiftLeftOp, other) def << (other: BigInt): UInt = this << other.toInt def << (other: UInt): UInt = binop(UInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other) @@ -488,12 +839,23 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi def === (that: BitPat): Bool = that === this def != (that: BitPat): Bool = that != this - /** Convert a UInt to an SInt by added a MSB zero */ + // REVIEW TODO: Is this really the common definition of zero extend? + // Can we just define UInt/SInt constructors on Bits as a reinterpret case? + /** Returns this UInt as a [[SInt]] with an additional zero in the MSB. + */ def zext(): SInt = pushOp(DefPrim(SInt(width + 1), ConvertOp, ref)) + + /** Returns this UInt as a [[SInt]], without changing width or bit value. The + * SInt is not guaranteed to have the same value (for example, if the MSB is + * high, it will be interpreted as a negative value). + */ def asSInt(): SInt = pushOp(DefPrim(SInt(width), AsSIntOp, ref)) + def asUInt(): UInt = this } +// REVIEW TODO: why not just have this be a companion object? Why the trait +// instead of object UInt? sealed trait UIntFactory { /** Create a UInt type with inferred width. */ def apply(): UInt = apply(NO_DIR, Width()) @@ -539,9 +901,10 @@ sealed trait UIntFactory { else Width() } -/** Provides a set of operations to create UInt types and literals. */ object UInt extends UIntFactory +// REVIEW TODO: Wait, wha?! Why does this exist? Things should be DRY and +// unambiguous. /** Provides a set of operations to create UInt types and literals. * Identical in functionality to the UInt companion object. */ object Bits extends UIntFactory @@ -601,7 +964,6 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non def asSInt(): SInt = this } -/** Provides a set of operations to create SInt types and literals. */ object SInt { /** Create an SInt type with inferred width. */ def apply(): SInt = apply(NO_DIR, Width()) @@ -626,6 +988,10 @@ object SInt { } } +// REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth +// operations on a Bool make sense? +/** A data type for booleans, defined as a single bit indicating true or false. + */ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Width(1), lit) { private[Chisel] override def cloneTypeWidth(w: Width): this.type = { require(!w.known || w.get == 1) @@ -637,26 +1003,43 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi Bool(value == 1).asInstanceOf[this.type] } + // REVIEW TODO: Why does this need to exist and have different conventions + // than Bits? def & (other: Bool): Bool = binop(Bool(), BitAndOp, other) def | (other: Bool): Bool = binop(Bool(), BitOrOp, other) def ^ (other: Bool): Bool = binop(Bool(), BitXorOp, other) + /** Outputs the logical OR of two Bools. + */ def || (that: Bool): Bool = this | that + + /** Outputs the logical AND of two Bools. + */ def && (that: Bool): Bool = this & that } object Bool { + /** Creates an empty Bool. + */ def apply(dir: Direction = NO_DIR): Bool = new Bool(dir) + + /** Creates Bool literal. + */ def apply(x: Boolean): Bool = new Bool(NO_DIR, Some(ULit(if (x) 1 else 0, Width(1)))) } object Mux { - /** Create a Mux - * @param cond a condition to determine which value to choose - * @param con the value chosen when cond is true or 1 - * @param alt the value chosen when cond is false or 0 + /** Creates a mux, whose output is one of the inputs depending on the + * value of the condition. + * + * @param cond condition determining the input to choose + * @param con the value chosen when `cond` is true + * @param alt the value chosen when `cond` is false * @example - * {{{ val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4)) }}} */ + * {{{ + * val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4)) + * }}} + */ def apply[T <: Data](cond: Bool, con: T, alt: T): T = (con, alt) match { // Handle Mux(cond, UInt, Bool) carefully so that the concrete type is UInt case (c: Bool, a: Bool) => doMux(cond, c, a).asInstanceOf[T] @@ -681,6 +1064,8 @@ object Mux { } } +// REVIEW TODO: Should the FIRRTL emission be part of Bits, with a separate +// Cat in stdlib that can do a reduction among multiple elements? object Cat { /** Combine data elements together * @param a Data to combine with @@ -688,6 +1073,7 @@ object Cat { * @return A UInt which is all of the bits combined together */ def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList) + /** Combine data elements together * @param r any number of other Data elements to be combined in order * @return A UInt which is all of the bits combined together @@ -706,9 +1092,11 @@ object Cat { object Bundle { private val keywords = HashSet[String]("flip", "asInput", "asOutput", "cloneType", "toBits") + def apply[T <: Bundle](b: => T)(implicit p: Parameters): T = { Builder.paramsScope(p.push){ b } } + //TODO @deprecated("Use Chisel.paramsScope object","08-01-2015") def apply[T <: Bundle](b: => T, f: PartialFunction[Any,Any]): T = { val q = Builder.getParams.alterPartial(f) @@ -716,35 +1104,49 @@ object Bundle { } } -/** Define a collection of datum of different types into a single coherent - whole. +/** Base class for data types defined as a bundle of other data types. + * + * Usage: extend this class (either as an anonymous or named class) and define + * members variables of [[Data]] subtypes to be elements in the Bundle. */ class Bundle extends Aggregate(NO_DIR) { private val _namespace = Builder.globalNamespace.child - /** Connect all elements contained in this to node 'that' - * @note The elements are checked for compatibility based on their name - * If elements are in src that are not in this Bundle no warning will be produced + // REVIEW TODO: perhaps deprecate to match FIRRTL semantics? Also needs + // strong connect operator. + /** Connect elements in this Bundle to elements in `that` on a best-effort + * (weak) basis, matching by type, orientation, and name. + * + * @note unconnected elements will NOT generate errors or warnings + * * @example - * {{{ // pass through all wires in this modules io to the sub module which have the same name - * // Note: ignores any extra defined in io - * mySubModule.io <> io }}} + * {{{ + * // Pass through wires in this module's io to those mySubModule's io, + * // matching by type, orientation, and name, and ignoring extra wires. + * mySubModule.io <> io + * }}} */ override def <> (that: Data): Unit = that match { case _: Bundle => this bulkConnect that case _ => this badConnect that } + // REVIEW TODO: should there be different semantics for this? Or just ban it? override def := (that: Data): Unit = this <> that lazy val elements: ListMap[String, Data] = ListMap(namedElts:_*) + /** Returns a best guess at whether a field in this Bundle is a user-defined + * Bundle element. + */ private def isBundleField(m: java.lang.reflect.Method) = m.getParameterTypes.isEmpty && !java.lang.reflect.Modifier.isStatic(m.getModifiers) && classOf[Data].isAssignableFrom(m.getReturnType) && !(Bundle.keywords contains m.getName) && !(m.getName contains '$') + /** Returns a list of elements in this Bundle. + */ private[Chisel] lazy val namedElts = { val nameMap = LinkedHashMap[String, Data]() val seen = HashSet[Data]() @@ -793,10 +1195,15 @@ class Bundle extends Aggregate(NO_DIR) { } object Module { - /** The wrapper method for all instantiations of modules - * @param m The module newly created + // TODO: update documentation when parameters gets removed from core Chisel + // and this gets simplified. + /** A wrapper method that all Module instantiations must be wrapped in + * (necessary to help Chisel track internal state). + * + * @param m the Module being created * @param p Parameters passed down implicitly from that it is created in - * @return A properly wrapped module that has been added to the Driver + * + * @return the input module `m` */ def apply[T <: Module](bc: => T)(implicit currParams: Parameters = Builder.getParams.push): T = { paramsScope(currParams) { @@ -815,12 +1222,19 @@ object Module { m }.connectImplicitIOs() } + //TODO @deprecated("Use Chisel.paramsScope object","08-01-2015") def apply[T <: Module](m: => T, f: PartialFunction[Any,Any]): T = { apply(m)(Builder.getParams.alterPartial(f)) } } +/** Abstract base class for Modules, which behave much like Verilog modules. + * These may contain both logic and state which are written in the Module + * body (constructor). + * + * @note Module instantiations must be wrapped in a Module() call. + */ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends HasId { private val _namespace = Builder.globalNamespace.child private[Chisel] val _commands = ArrayBuffer[Command]() @@ -830,7 +1244,9 @@ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends HasId { /** Name of the instance. */ val name = Builder.globalNamespace.name(getClass.getName.split('.').last) - /** the I/O for this module */ + /** IO for this Module. At the Scala level (pre-FIRRTL transformations), + * connections in and out of a Module may only go through `io` elements. + */ def io: Bundle val clock = Clock(INPUT) val reset = Bool(INPUT) @@ -880,45 +1296,59 @@ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends HasId { def printf(message: String, args: Bits*): Unit = {} } -/** This class allows the connection to modules defined outside of chisel. +/** Defines a black box, which is a module that can be referenced from within + * Chisel, but is not defined in the emitted Verilog. Useful for connecting + * to RTL modules defined outside Chisel. + * * @example - * {{{ class DSP48E1 extends BlackBox { - * val io = new Bundle // Create I/O with same as DSP - * val dspParams = new VerilogParameters // Create Parameters to be specified - * setVerilogParams(dspParams) - * // Implement functionality of DSP to allow simulation verification - * } }}} + * {{{ + * class DSP48E1 extends BlackBox { + * val io = new Bundle // Create I/O with same as DSP + * val dspParams = new VerilogParameters // Create Parameters to be specified + * setVerilogParams(dspParams) + * // Implement functionality of DSP to allow simulation verification + * } + * }}} */ // TODO: actually implement BlackBox (this hack just allows them to compile) +// REVIEW TODO: make Verilog parameters part of the constructor interface? abstract class BlackBox(_clock: Clock = null, _reset: Bool = null) extends Module(_clock = _clock, _reset = _reset) { def setVerilogParameters(s: String): Unit = {} } -/** An object to create conditional logic. - * @example - * {{{ - * when ( myData === UInt(3) ) { - * ... // Some logic - * } .elsewhen ( myData === UInt(1) ) { - * ... // Some logic - * } .otherwise { - * ... // Some logic - * } }}} - */ object when { - /** @param cond condition to execute upon - * @param block a section of logic to enable if cond is true */ + /** Create a `when` condition block, where whether a block of logic is + * executed or not depends on the conditional. + * + * @param cond condition to execute upon + * @param block logic that runs only if `cond` is true + * + * @example + * {{{ + * when ( myData === UInt(3) ) { + * // Some logic to run when myData equals 3. + * } .elsewhen ( myData === UInt(1) ) { + * // Some logic to run when myData equals 1. + * } .otherwise { + * // Some logic to run when myData is neither 3 nor 1. + * } + * }}} + */ def apply(cond: => Bool)(block: => Unit): WhenContext = { new WhenContext(cond)(block) } } class WhenContext(cond: => Bool)(block: => Unit) { - /** execute block when alternative cond is true */ + /** 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)) - /** execute block by default */ + /** 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) @@ -934,6 +1364,8 @@ class WhenContext(cond: => Bool)(block: => Unit) { } } +// 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 = |
