// See LICENSE for license details. package uncore.tilelink2 import Chisel._ import chisel3.util.{ReadyValidIO} import diplomacy._ import util.{AsyncQueueSource, AsyncQueueSink, GenericParameterizedBundle} abstract class TLBundleBase(params: TLBundleParameters) extends GenericParameterizedBundle(params) // common combos in lazy policy: // Put + Acquire // Release + AccessAck object TLMessages { // A B C D E val PutFullData = UInt(0) // . . => AccessAck val PutPartialData = UInt(1) // . . => AccessAck val ArithmeticData = UInt(2) // . . => AccessAckData val LogicalData = UInt(3) // . . => AccessAckData val Get = UInt(4) // . . => AccessAckData val Hint = UInt(5) // . . => HintAck val Acquire = UInt(6) // . => Grant[Data] val Probe = UInt(6) // . => ProbeAck[Data] val AccessAck = UInt(0) // . . val AccessAckData = UInt(1) // . . val HintAck = UInt(2) // . . //val PutThroughData = UInt(3) // . // future extension ? val ProbeAck = UInt(4) // . val ProbeAckData = UInt(5) // . val Release = UInt(6) // . => ReleaseAck val ReleaseData = UInt(7) // . => ReleaseAck val Grant = UInt(4) // . => GrantAck val GrantData = UInt(5) // . => GrantAck val ReleaseAck = UInt(6) // . val GrantAck = UInt(0) // . def isA(x: UInt) = x <= Acquire def isB(x: UInt) = x <= Probe def isC(x: UInt) = x <= ReleaseData def isD(x: UInt) = x <= ReleaseAck } object TLPermissions { // Cap types (Grant = new permissions, Probe = permisions <= target) val toT = UInt(0) val toB = UInt(1) val toN = UInt(2) def isCap(x: UInt) = x <= toN // Grow types (Acquire = permissions >= target) val NtoB = UInt(0) val NtoT = UInt(1) val BtoT = UInt(2) def isGrow(x: UInt) = x <= BtoT // Shrink types (ProbeAck, Release) val TtoB = UInt(0) val TtoN = UInt(1) val BtoN = UInt(2) def isShrink(x: UInt) = x <= BtoN // Report types (ProbeAck) val TtoT = UInt(3) val BtoB = UInt(4) val NtoN = UInt(5) def isReport(x: UInt) = x <= NtoN } object TLAtomics { // Arithmetic types val MIN = UInt(0) val MAX = UInt(1) val MINU = UInt(2) val MAXU = UInt(3) val ADD = UInt(4) def isArithmetic(x: UInt) = x <= ADD // Logical types val XOR = UInt(0) val OR = UInt(1) val AND = UInt(2) val SWAP = UInt(3) def isLogical(x: UInt) = x <= SWAP } sealed trait TLChannel extends TLBundleBase { val channelName: String } sealed trait TLDataChannel extends TLChannel sealed trait TLAddrChannel extends TLDataChannel final class TLBundleA(params: TLBundleParameters) extends TLBundleBase(params) with TLAddrChannel { val channelName = "'A' channel" // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) // amo_opcode || perms || hint val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) } final class TLBundleB(params: TLBundleParameters) extends TLBundleBase(params) with TLAddrChannel { val channelName = "'B' channel" // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val address = UInt(width = params.addressBits) // from // variable fields during multibeat: val mask = UInt(width = params.dataBits/8) val data = UInt(width = params.dataBits) } final class TLBundleC(params: TLBundleParameters) extends TLBundleBase(params) with TLAddrChannel { val channelName = "'C' channel" // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 3) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // from val address = UInt(width = params.addressBits) // to // variable fields during multibeat: val data = UInt(width = params.dataBits) val error = Bool() // AccessAck[Data] } final class TLBundleD(params: TLBundleParameters) extends TLBundleBase(params) with TLDataChannel { val channelName = "'D' channel" // fixed fields during multibeat: val opcode = UInt(width = 3) val param = UInt(width = 2) val size = UInt(width = params.sizeBits) val source = UInt(width = params.sourceBits) // to val sink = UInt(width = params.sinkBits) // from val addr_lo = UInt(width = params.addrLoBits) // instead of mask // variable fields during multibeat: val data = UInt(width = params.dataBits) val error = Bool() // AccessAck[Data], Grant[Data] } final class TLBundleE(params: TLBundleParameters) extends TLBundleBase(params) with TLChannel { val channelName = "'E' channel" val sink = UInt(width = params.sinkBits) // to } class TLBundle(params: TLBundleParameters) extends TLBundleBase(params) { val a = Decoupled(new TLBundleA(params)) val b = Decoupled(new TLBundleB(params)).flip val c = Decoupled(new TLBundleC(params)) val d = Decoupled(new TLBundleD(params)).flip val e = Decoupled(new TLBundleE(params)) } object TLBundle { def apply(params: TLBundleParameters) = new TLBundle(params) } final class DecoupledSnoop[+T <: Data](gen: T) extends Bundle { val ready = Bool() val valid = Bool() val bits = gen.asOutput def fire(dummy: Int = 0) = ready && valid override def cloneType: this.type = new DecoupledSnoop(gen).asInstanceOf[this.type] } object DecoupledSnoop { def apply[T <: Data](i: DecoupledIO[T]) = { val out = Wire(new DecoupledSnoop(i.bits)) out.ready := i.ready out.valid := i.valid out.bits := i.bits out } } class TLBundleSnoop(params: TLBundleParameters) extends TLBundleBase(params) { val a = new DecoupledSnoop(new TLBundleA(params)) val b = new DecoupledSnoop(new TLBundleB(params)) val c = new DecoupledSnoop(new TLBundleC(params)) val d = new DecoupledSnoop(new TLBundleD(params)) val e = new DecoupledSnoop(new TLBundleE(params)) } object TLBundleSnoop { def apply(x: TLBundle) = { val out = Wire(new TLBundleSnoop(x.params)) out.a <> DecoupledSnoop(x.a) out.b <> DecoupledSnoop(x.b) out.c <> DecoupledSnoop(x.c) out.d <> DecoupledSnoop(x.d) out.e <> DecoupledSnoop(x.e) out } } final class AsyncBundle[T <: Data](val depth: Int, gen: T) extends Bundle { require (isPow2(depth)) val mem = Vec(depth, gen) val ridx = UInt(width = log2Up(depth)+1).flip val widx = UInt(width = log2Up(depth)+1) val ridx_valid = Bool().flip val widx_valid = Bool() val source_reset_n = Bool() val sink_reset_n = Bool().flip override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type] } object FromAsyncBundle { def apply[T <: Data](x: AsyncBundle[T], sync: Int = 3): DecoupledIO[T] = { val sink = Module(new AsyncQueueSink(x.mem(0), x.depth, sync)) x.ridx := sink.io.ridx x.ridx_valid := sink.io.ridx_valid sink.io.widx := x.widx sink.io.widx_valid := x.widx_valid sink.io.mem := x.mem sink.io.source_reset_n := x.source_reset_n x.sink_reset_n := !sink.reset val out = Wire(Decoupled(x.mem(0))) out.valid := sink.io.deq.valid out.bits := sink.io.deq.bits sink.io.deq.ready := out.ready out } } object ToAsyncBundle { def apply[T <: Data](x: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): AsyncBundle[T] = { val source = Module(new AsyncQueueSource(x.bits, depth, sync)) source.io.enq.valid := x.valid source.io.enq.bits := x.bits x.ready := source.io.enq.ready val out = Wire(new AsyncBundle(depth, x.bits)) source.io.ridx := out.ridx source.io.ridx_valid := out.ridx_valid out.mem := source.io.mem out.widx := source.io.widx out.widx_valid := source.io.widx_valid source.io.sink_reset_n := out.sink_reset_n out.source_reset_n := !source.reset out } } class TLAsyncBundleBase(params: TLAsyncBundleParameters) extends GenericParameterizedBundle(params) class TLAsyncBundle(params: TLAsyncBundleParameters) extends TLAsyncBundleBase(params) { val a = new AsyncBundle(params.depth, new TLBundleA(params.base)) val b = new AsyncBundle(params.depth, new TLBundleB(params.base)).flip val c = new AsyncBundle(params.depth, new TLBundleC(params.base)) val d = new AsyncBundle(params.depth, new TLBundleD(params.base)).flip val e = new AsyncBundle(params.depth, new TLBundleE(params.base)) }