1
0

tilelink2 RegField: clarify restrictions on functions

RegMapper is fundamentaly DecoupledIO.
Let the user take advantage of this.
Clarify that rules on data handling.
This commit is contained in:
Wesley W. Terpstra 2016-10-02 00:00:32 -07:00 committed by Andrew Waterman
parent bff0ffa428
commit 8a268268ad

View File

@ -3,7 +3,7 @@
package uncore.tilelink2 package uncore.tilelink2
import Chisel._ import Chisel._
import chisel3.util.{Irrevocable, IrrevocableIO} import chisel3.util.{ReadyValidIO}
import util.{SimpleRegIO} import util.{SimpleRegIO}
case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt)) case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
@ -12,9 +12,8 @@ object RegReadFn
// (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt) // (ivalid: Bool, oready: Bool) => (iready: Bool, ovalid: Bool, data: UInt)
// iready may combinationally depend on oready // iready may combinationally depend on oready
// all other combinational dependencies forbidden (e.g. ovalid <= ivalid) // all other combinational dependencies forbidden (e.g. ovalid <= ivalid)
// iready must eventually go high without requiring ivalid to go high
// ovalid must eventually go high without requiring oready to go high
// effects must become visible on the cycle after ovalid && oready // effects must become visible on the cycle after ovalid && oready
// data is only inspected when ovalid && oready
implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) =
new RegReadFn(false, x) new RegReadFn(false, x)
implicit def apply(x: RegisterReadIO[UInt]): RegReadFn = implicit def apply(x: RegisterReadIO[UInt]): RegReadFn =
@ -25,17 +24,14 @@ object RegReadFn
}) })
// (ready: Bool) => (valid: Bool, data: UInt) // (ready: Bool) => (valid: Bool, data: UInt)
// valid must not combinationally depend on ready // valid must not combinationally depend on ready
// valid must eventually go high without requiring ready to go high
// => this means that reading cannot trigger creation of the output data
// if you need this, use the more general i&o ready-valid method above
// effects must become visible on the cycle after valid && ready // effects must become visible on the cycle after valid && ready
implicit def apply(x: Bool => (Bool, UInt)) = implicit def apply(x: Bool => (Bool, UInt)) =
new RegReadFn(true, { case (_, oready) => new RegReadFn(true, { case (_, oready) =>
val (ovalid, data) = x(oready) val (ovalid, data) = x(oready)
(Bool(true), ovalid, data) (Bool(true), ovalid, data)
}) })
// read from a IrrevocableIO (only safe if there is a consistent source of data) // read from a ReadyValidIO (only safe if there is a consistent source of data)
implicit def apply(x: IrrevocableIO[UInt]):RegReadFn = RegReadFn(ready => { x.ready := ready; (x.valid, x.bits) }) implicit def apply(x: ReadyValidIO[UInt]):RegReadFn = RegReadFn(ready => { x.ready := ready; (x.valid, x.bits) })
// read from a register // read from a register
implicit def apply(x: UInt):RegReadFn = RegReadFn(ready => (Bool(true), x)) implicit def apply(x: UInt):RegReadFn = RegReadFn(ready => (Bool(true), x))
// noop // noop
@ -48,9 +44,8 @@ object RegWriteFn
// (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool) // (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool)
// iready may combinationally depend on both oready and data // iready may combinationally depend on both oready and data
// all other combinational dependencies forbidden (e.g. ovalid <= ivalid) // all other combinational dependencies forbidden (e.g. ovalid <= ivalid)
// iready must eventually go high without requiring ivalid to go high
// ovalid must eventually go high without requiring oready to go high
// effects must become visible on the cycle after ovalid && oready // effects must become visible on the cycle after ovalid && oready
// data should only be used for an effect when ivalid && iready
implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) =
new RegWriteFn(false, x) new RegWriteFn(false, x)
implicit def apply(x: RegisterWriteIO[UInt]): RegWriteFn = implicit def apply(x: RegisterWriteIO[UInt]): RegWriteFn =
@ -62,15 +57,15 @@ object RegWriteFn
}) })
// (valid: Bool, data: UInt) => (ready: Bool) // (valid: Bool, data: UInt) => (ready: Bool)
// ready may combinationally depend on data (but not valid) // ready may combinationally depend on data (but not valid)
// ready must eventually go high without requiring valid to go high
// effects must become visible on the cycle after valid && ready // effects must become visible on the cycle after valid && ready
implicit def apply(x: (Bool, UInt) => Bool) = implicit def apply(x: (Bool, UInt) => Bool) =
// combinational => data valid on oready // combinational => data valid on oready
new RegWriteFn(true, { case (_, oready, data) => new RegWriteFn(true, { case (_, oready, data) =>
(Bool(true), x(oready, data)) (Bool(true), x(oready, data))
}) })
// write to a IrrevocableIO (only safe if there is a consistent sink draining data) // write to a DecoupledIO (only safe if there is a consistent sink draining data)
implicit def apply(x: IrrevocableIO[UInt]): RegWriteFn = RegWriteFn((valid, data) => { x.valid := valid; x.bits := data; x.ready }) // NOTE: this is not an IrrevocableIO (even on TL2) because other fields could cause a lowered valid
implicit def apply(x: DecoupledIO[UInt]): RegWriteFn = RegWriteFn((valid, data) => { x.valid := valid; x.bits := data; x.ready })
// updates a register (or adds a mux to a wire) // updates a register (or adds a mux to a wire)
implicit def apply(x: UInt): RegWriteFn = RegWriteFn((valid, data) => { when (valid) { x := data }; Bool(true) }) implicit def apply(x: UInt): RegWriteFn = RegWriteFn((valid, data) => { when (valid) { x := data }; Bool(true) })
// noop // noop