From 8a268268adb6c704c4f1ac9a678bb9bb6c1d171f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 2 Oct 2016 00:00:32 -0700 Subject: [PATCH] tilelink2 RegField: clarify restrictions on functions RegMapper is fundamentaly DecoupledIO. Let the user take advantage of this. Clarify that rules on data handling. --- .../scala/uncore/tilelink2/RegField.scala | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala index 60cf1dc8..61fc45a4 100644 --- a/src/main/scala/uncore/tilelink2/RegField.scala +++ b/src/main/scala/uncore/tilelink2/RegField.scala @@ -3,7 +3,7 @@ package uncore.tilelink2 import Chisel._ -import chisel3.util.{Irrevocable, IrrevocableIO} +import chisel3.util.{ReadyValidIO} import util.{SimpleRegIO} 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) // iready may combinationally depend on oready // 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 + // data is only inspected when ovalid && oready implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = new RegReadFn(false, x) implicit def apply(x: RegisterReadIO[UInt]): RegReadFn = @@ -25,17 +24,14 @@ object RegReadFn }) // (ready: Bool) => (valid: Bool, data: UInt) // 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 implicit def apply(x: Bool => (Bool, UInt)) = new RegReadFn(true, { case (_, oready) => val (ovalid, data) = x(oready) (Bool(true), ovalid, data) }) - // read from a IrrevocableIO (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) }) + // read from a ReadyValidIO (only safe if there is a consistent source of data) + implicit def apply(x: ReadyValidIO[UInt]):RegReadFn = RegReadFn(ready => { x.ready := ready; (x.valid, x.bits) }) // read from a register implicit def apply(x: UInt):RegReadFn = RegReadFn(ready => (Bool(true), x)) // noop @@ -48,9 +44,8 @@ object RegWriteFn // (ivalid: Bool, oready: Bool, data: UInt) => (iready: Bool, ovalid: Bool) // iready may combinationally depend on both oready and data // 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 + // data should only be used for an effect when ivalid && iready implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = new RegWriteFn(false, x) implicit def apply(x: RegisterWriteIO[UInt]): RegWriteFn = @@ -62,15 +57,15 @@ object RegWriteFn }) // (valid: Bool, data: UInt) => (ready: Bool) // 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 implicit def apply(x: (Bool, UInt) => Bool) = // combinational => data valid on oready new RegWriteFn(true, { case (_, oready, data) => (Bool(true), x(oready, data)) }) - // write to a IrrevocableIO (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 }) + // write to a DecoupledIO (only safe if there is a consistent sink draining data) + // 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) implicit def apply(x: UInt): RegWriteFn = RegWriteFn((valid, data) => { when (valid) { x := data }; Bool(true) }) // noop