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:
		
				
					committed by
					
						 Andrew Waterman
						Andrew Waterman
					
				
			
			
				
	
			
			
			
						parent
						
							bff0ffa428
						
					
				
				
					commit
					8a268268ad
				
			| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user