From 6a378e79e381f39e17ffa619041de496ecb74d81 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 2 Sep 2016 21:42:37 -0700 Subject: [PATCH] tilelink2: allow 0-stage backpressure in combinational regmap --- .../scala/uncore/tilelink2/RegField.scala | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/RegField.scala b/src/main/scala/uncore/tilelink2/RegField.scala index b546cafc..2dded47e 100644 --- a/src/main/scala/uncore/tilelink2/RegField.scala +++ b/src/main/scala/uncore/tilelink2/RegField.scala @@ -10,14 +10,20 @@ 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) - // effects must become visible only on the cycle after ovalid && oready + // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool) => (Bool, Bool, UInt)) = new RegReadFn(false, x) - // (ofire: Bool) => (data: UInt) - // effects must become visible on the cycle after ofire - implicit def apply(x: Bool => UInt) = + // (ready: Bool) => (valid: Bool, data: UInt) + // valid must not combinationally depend on ready + // effects must become visible on the cycle after valid && ready + // ready is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) + // ... which is irrelevant if you can service the read immediately + // ... if irrevocable, you may start reading on rising ready and raise valid when done + // ... otherwise, use the more general in&out ready-valid method above + implicit def apply(x: Bool => (Bool, UInt)) = new RegReadFn(true, { case (_, oready) => - (Bool(true), Bool(true), x(oready)) + val (ovalid, data) = x(oready) + (Bool(true), ovalid, data) }) // read from a register implicit def apply(x: UInt) = @@ -37,15 +43,20 @@ 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) - // effects must become visible only on the cycle after ovalid && oready + // effects must become visible on the cycle after ovalid && oready implicit def apply(x: (Bool, Bool, UInt) => (Bool, Bool)) = new RegWriteFn(false, x) - // (ofire: Bool, data: UInt) => () - // effects must become visible on the cycle after ofire - implicit def apply(x: (Bool, UInt) => Unit) = + // (valid: Bool, data: UInt) => (ready: Bool) + // ready may combinationally depend on data (but not valid) + // effects must become visible on the cycle after valid && ready + // valid is only guaranteed to stay high if fed by an Irrevocable (eg: TL2 or concurrency > 0) + // ... which is irrelevant if you can service the write immediately + // ... if irrevocable, you may start writing on rising valid and raise ready when done + // ... otherwise, use the more general in&out ready-valid method above + implicit def apply(x: (Bool, UInt) => Bool) = + // combinational => data valid on oready new RegWriteFn(true, { case (_, oready, data) => - x(oready, data) - (Bool(true), Bool(true)) + (Bool(true), x(oready, data)) }) // updates a register implicit def apply(x: UInt) =