diff options
| author | ducky | 2016-05-05 11:50:39 -0700 |
|---|---|---|
| committer | ducky | 2016-05-05 11:50:39 -0700 |
| commit | 9036d96bb032c19de31131f2296120e708cbc3dc (patch) | |
| tree | cf17173fab309b09670ca7529680e09d61341451 /chiselFrontend/src/main/scala/Chisel/Mem.scala | |
| parent | 623a301df1f5a1954f8e4a64ef97c99c3900da28 (diff) | |
Move Chisel API into separate chiselFrontend compilation unit in preparation for source locator macros
Diffstat (limited to 'chiselFrontend/src/main/scala/Chisel/Mem.scala')
| -rw-r--r-- | chiselFrontend/src/main/scala/Chisel/Mem.scala | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/Chisel/Mem.scala b/chiselFrontend/src/main/scala/Chisel/Mem.scala new file mode 100644 index 00000000..17ac9ca5 --- /dev/null +++ b/chiselFrontend/src/main/scala/Chisel/Mem.scala @@ -0,0 +1,123 @@ +// See LICENSE for license details. + +package Chisel + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ + +object Mem { + @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") + 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) + pushCommand(DefMemory(mem, mt, size)) // TODO multi-clock + 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/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 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 = { + makePort(idx, MemPortDirection.WRITE) := 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 = { + 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. + * + * 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. + * + * @note when multiple conflicting writes are performed on a Mem element, the + * result is undefined (unlike Vec, where the last assignment wins) + */ +sealed class Mem[T <: Data](t: T, length: Int) extends MemBase(t, length) + +object SeqMem { + @deprecated("SeqMem argument order should be size, t; this will be removed by the official release", "chisel3") + 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) + pushCommand(DefSeqMemory(mem, mt, size)) // TODO multi-clock + mem + } +} + +/** 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. + * + * @note when multiple conflicting writes are performed on a Mem element, the + * 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 = { + val a = Wire(UInt()) + when (enable) { a := addr } + read(a) + } +} |
