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:
parent
bff0ffa428
commit
8a268268ad
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user