1
0

New metadata-based coherence API

This commit is contained in:
Henry Cook
2015-02-28 17:02:13 -08:00
parent 0a8722e881
commit 1bed6ea498
9 changed files with 2117 additions and 1851 deletions

View File

@ -8,30 +8,35 @@ import scala.math.max
// external requirements or design space exploration
//
case object TLId extends Field[String] // Unique name per network
case object TLCoherence extends Field[CoherencePolicy]
case object TLAddrBits extends Field[Int]
case object TLCoherencePolicy extends Field[CoherencePolicy]
case object TLBlockAddrBits extends Field[Int]
case object TLManagerXactIdBits extends Field[Int]
case object TLClientXactIdBits extends Field[Int]
case object TLDataBits extends Field[Int]
case object TLDataBeats extends Field[Int]
case object TLNetworkIsOrderedP2P extends Field[Boolean]
abstract trait TileLinkParameters extends UsesParameters {
val tlBlockAddrBits = params(TLAddrBits)
val tlBlockAddrBits = params(TLBlockAddrBits)
val tlClientXactIdBits = params(TLClientXactIdBits)
val tlManagerXactIdBits = params(TLManagerXactIdBits)
val tlDataBits = params(TLDataBits)
val tlDataBeats = params(TLDataBeats)
val tlCoh = params(TLCoherencePolicy)
val tlWriteMaskBits = if(tlDataBits/8 < 1) 1 else tlDataBits/8
val tlBeatAddrBits = log2Up(tlDataBeats)
val tlByteAddrBits = log2Up(tlWriteMaskBits)
val tlAtomicOpcodeBits = M_SZ
val tlUncachedOperandSizeBits = MT_SZ
val tlSubblockUnionBits = max(tlWriteMaskBits,
val tlMemoryOpcodeBits = M_SZ
val tlMemoryOperandSizeBits = MT_SZ
val tlAcquireTypeBits = max(log2Up(Acquire.nBuiltInTypes),
tlCoh.acquireTypeWidth)
val tlAcquireUnionBits = max(tlWriteMaskBits,
(tlByteAddrBits +
tlUncachedOperandSizeBits +
tlAtomicOpcodeBits)) + 1
val co = params(TLCoherence)
val networkPreservesPointToPointOrdering = false //TODO: check physical network type
tlMemoryOperandSizeBits +
tlMemoryOpcodeBits)) + 1
val tlGrantTypeBits = max(log2Up(Grant.nBuiltInTypes),
tlCoh.grantTypeWidth) + 1
val tlNetworkPreservesPointToPointOrdering = params(TLNetworkIsOrderedP2P)
}
abstract class TLBundle extends Bundle with TileLinkParameters
@ -50,8 +55,8 @@ trait ClientToClientChannel extends TileLinkChannel // Unused for now
trait HasCacheBlockAddress extends TLBundle {
val addr_block = UInt(width = tlBlockAddrBits)
def conflicts[T <: HasCacheBlockAddress](that: T) = this.addr_block === that.addr_block
def conflicts[T <: HasCacheBlockAddress](addr: UInt) = this.addr_block === addr
def conflicts(that: HasCacheBlockAddress) = this.addr_block === that.addr_block
def conflicts(addr: UInt) = this.addr_block === addr
}
trait HasTileLinkBeatId extends TLBundle {
@ -66,8 +71,9 @@ trait HasManagerTransactionId extends TLBundle {
val manager_xact_id = Bits(width = tlManagerXactIdBits)
}
abstract trait HasTileLinkData extends HasTileLinkBeatId {
trait HasTileLinkData extends HasTileLinkBeatId {
val data = UInt(width = tlDataBits)
def hasData(dummy: Int = 0): Bool
def hasMultibeatData(dummy: Int = 0): Bool
}
@ -79,95 +85,81 @@ class Acquire extends ClientToManagerChannel
with HasClientTransactionId
with HasTileLinkData {
// Actual bundle fields
val builtin_type = Bool()
val a_type = UInt(width = max(log2Up(Acquire.nBuiltinAcquireTypes), co.acquireTypeWidth))
val subblock = Bits(width = tlSubblockUnionBits)
val is_builtin_type = Bool()
val a_type = UInt(width = tlAcquireTypeBits)
val union = Bits(width = tlAcquireUnionBits)
// Utility funcs for accessing subblock union
val opSizeOff = tlByteAddrBits + 1
val opCodeOff = tlUncachedOperandSizeBits + opSizeOff
val opMSB = tlAtomicOpcodeBits + opCodeOff
def allocate(dummy: Int = 0) = subblock(0)
def addr_byte(dummy: Int = 0) = subblock(opSizeOff-1, 1)
def op_size(dummy: Int = 0) = subblock(opCodeOff-1, opSizeOff)
def op_code(dummy: Int = 0) = subblock(opMSB-1, opCodeOff)
def write_mask(dummy: Int = 0) = subblock(tlWriteMaskBits, 1)
def addr(dummy: Int = 0) = Cat(addr_block, addr_beat, this.addr_byte(0))
val opCodeOff = 1
val opSizeOff = tlMemoryOpcodeBits + opCodeOff
val addrByteOff = tlMemoryOperandSizeBits + opSizeOff
val addrByteMSB = tlByteAddrBits + addrByteOff
def allocate(dummy: Int = 0) = union(0)
def op_code(dummy: Int = 0) = Mux(hasData(), M_XWR, union(opSizeOff-1, opCodeOff))
def op_size(dummy: Int = 0) = union(addrByteOff-1, opSizeOff)
def addr_byte(dummy: Int = 0) = union(addrByteMSB-1, addrByteOff)
def write_mask(dummy: Int = 0) = union(tlWriteMaskBits, 1)
def addr(dummy: Int = 0) = Cat(this.addr_block, this.addr_beat, this.addr_byte())
// Other helper funcs
def is(t: UInt) = a_type === t
def hasData(dummy: Int = 0): Bool = builtin_type && Acquire.typesWithData.contains(a_type)
def isBuiltInType(dummy: Int = 0): Bool = is_builtin_type
def hasMultibeatData(dummy: Int = 0): Bool = Bool(tlDataBeats > 1) && builtin_type &&
def isSubBlockType(dummy: Int = 0): Bool = isBuiltInType() && Acquire.typesOnSubBlocks.contains(a_type)
// Assumes no custom types have data
def hasData(dummy: Int = 0): Bool = isBuiltInType() && Acquire.typesWithData.contains(a_type)
def hasMultibeatData(dummy: Int = 0): Bool = Bool(tlDataBeats > 1) && isBuiltInType() &&
Acquire.typesWithMultibeatData.contains(a_type)
//TODO: This function is a hack to support Rocket icache snooping Rocket nbdcache:
def requiresSelfProbe(dummy: Int = 0) = builtin_type && Acquire.requiresSelfProbe(a_type)
def requiresSelfProbe(dummy: Int = 0) = isBuiltInType() && a_type === Acquire.getBlockType
def makeProbe(meta: ManagerMetadata = co.managerMetadataOnFlush): Probe =
Probe(co.getProbeType(this, meta), this.addr_block)
def makeGrant(
manager_xact_id: UInt,
meta: ManagerMetadata = co.managerMetadataOnFlush,
addr_beat: UInt = UInt(0),
data: UInt = UInt(0)): Grant = {
Grant(
builtin_type = this.builtin_type,
g_type = co.getGrantType(this, meta),
client_xact_id = this.client_xact_id,
manager_xact_id = manager_xact_id,
addr_beat = addr_beat,
data = data
)
def getBuiltInGrantType(dummy: Int = 0): UInt = {
MuxLookup(this.a_type, Grant.ackType, Array(
Acquire.getType -> Grant.dataBeatType,
Acquire.getBlockType -> Grant.dataBlockType,
Acquire.putType -> Grant.ackType,
Acquire.putBlockType -> Grant.ackType,
Acquire.putAtomicType -> Grant.dataBeatType))
}
}
object Acquire {
val nBuiltinAcquireTypes = 5
val nBuiltInTypes = 5
//TODO: Use Enum
def uncachedRead = UInt(0)
def uncachedReadBlock = UInt(1)
def uncachedWrite = UInt(2)
def uncachedWriteBlock = UInt(3)
def uncachedAtomic = UInt(4)
def typesWithData = Vec(uncachedWrite, uncachedWriteBlock, uncachedAtomic)
def typesWithMultibeatData = Vec(uncachedWriteBlock)
def requiresOuterRead(a_type: UInt) = a_type != uncachedWriteBlock
def requiresOuterWrite(a_type: UInt) = typesWithData.contains(a_type)
//TODO: This function is a hack to support Rocket icache snooping Rocket nbdcache:
def requiresSelfProbe(a_type: UInt) = a_type === uncachedReadBlock
def getType = UInt("b000")
def getBlockType = UInt("b001")
def putType = UInt("b010")
def putBlockType = UInt("b011")
def putAtomicType = UInt("b100")
def typesWithData = Vec(putType, putBlockType, putAtomicType)
def typesWithMultibeatData = Vec(putBlockType)
def typesOnSubBlocks = Vec(putType, getType, putAtomicType)
def fullWriteMask = SInt(-1, width = new Acquire().tlWriteMaskBits).toUInt
// Most generic constructor
def apply(
builtin_type: Bool,
is_builtin_type: Bool,
a_type: Bits,
client_xact_id: UInt,
addr_block: UInt,
addr_beat: UInt = UInt(0),
data: UInt = UInt(0),
subblock: UInt = UInt(0)): Acquire = {
union: UInt = UInt(0)): Acquire = {
val acq = new Acquire
acq.builtin_type := builtin_type
acq.is_builtin_type := is_builtin_type
acq.a_type := a_type
acq.client_xact_id := client_xact_id
acq.addr_block := addr_block
acq.addr_beat := addr_beat
acq.data := data
acq.subblock := subblock
acq.union := union
acq
}
// For cached types
def apply(a_type: Bits, client_xact_id: UInt, addr_block: UInt): Acquire = {
apply(
builtin_type = Bool(false),
a_type = a_type,
client_xact_id = client_xact_id,
addr_block = addr_block)
}
// Copy constructor
def apply(a: Acquire): Acquire = {
val acq = new Acquire
@ -177,58 +169,73 @@ object Acquire {
}
// Asks for a single TileLink beat of data
object UncachedRead {
object Get {
def apply(
client_xact_id: UInt,
addr_block: UInt,
addr_beat: UInt,
alloc: Bool = Bool(true)): Acquire = {
Acquire(
builtin_type = Bool(true),
a_type = Acquire.uncachedRead,
is_builtin_type = Bool(true),
a_type = Acquire.getType,
client_xact_id = client_xact_id,
addr_block = addr_block,
addr_beat = addr_beat,
subblock = alloc)
union = Cat(M_XRD, alloc))
}
}
// Asks for an entire cache block of data
object UncachedReadBlock {
object GetBlock {
def apply(
client_xact_id: UInt = UInt(0),
addr_block: UInt,
alloc: Bool = Bool(true)): Acquire = {
Acquire(
builtin_type = Bool(true),
a_type = Acquire.uncachedReadBlock,
is_builtin_type = Bool(true),
a_type = Acquire.getBlockType,
client_xact_id = client_xact_id,
addr_block = addr_block,
subblock = alloc.toUInt)
union = Cat(M_XRD, alloc))
}
}
object UncachedWrite {
// Writes up to a single TileLink beat of data, using mask
object Put {
def apply(
client_xact_id: UInt,
addr_block: UInt,
addr_beat: UInt,
data: UInt,
write_mask: UInt = Acquire.fullWriteMask,
alloc: Bool = Bool(true)): Acquire = {
write_mask: UInt = Acquire.fullWriteMask): Acquire = {
Acquire(
builtin_type = Bool(true),
a_type = Acquire.uncachedWrite,
is_builtin_type = Bool(true),
a_type = Acquire.putType,
addr_block = addr_block,
addr_beat = addr_beat,
client_xact_id = client_xact_id,
data = data,
subblock = Cat(write_mask, alloc))
union = Cat(write_mask, Bool(true)))
}
}
// For full block of data
object UncachedWriteBlock {
// Writes an entire cache block of data
object PutBlock {
def apply(
client_xact_id: UInt,
addr_block: UInt,
addr_beat: UInt,
data: UInt,
write_mask: UInt): Acquire = {
Acquire(
is_builtin_type = Bool(true),
a_type = Acquire.putBlockType,
client_xact_id = client_xact_id,
addr_block = addr_block,
addr_beat = addr_beat,
data = data,
union = Cat(write_mask, (write_mask != Acquire.fullWriteMask)))
}
def apply(
client_xact_id: UInt,
addr_block: UInt,
@ -236,17 +243,18 @@ object UncachedWriteBlock {
data: UInt,
alloc: Bool = Bool(true)): Acquire = {
Acquire(
builtin_type = Bool(true),
a_type = Acquire.uncachedWriteBlock,
is_builtin_type = Bool(true),
a_type = Acquire.putBlockType,
client_xact_id = client_xact_id,
addr_block = addr_block,
addr_beat = addr_beat,
data = data,
subblock = Cat(Acquire.fullWriteMask, alloc))
union = Cat(Acquire.fullWriteMask, alloc))
}
}
object UncachedAtomic {
// Performs an atomic operation in the outer memory
object PutAtomic {
def apply(
client_xact_id: UInt,
addr_block: UInt,
@ -256,48 +264,30 @@ object UncachedAtomic {
operand_size: UInt,
data: UInt): Acquire = {
Acquire(
builtin_type = Bool(true),
a_type = Acquire.uncachedAtomic,
is_builtin_type = Bool(true),
a_type = Acquire.putAtomicType,
client_xact_id = client_xact_id,
addr_block = addr_block,
addr_beat = addr_beat,
data = data,
subblock = Cat(atomic_opcode, operand_size, addr_byte, Bool(true)))
union = Cat(addr_byte, operand_size, atomic_opcode, Bool(true)))
}
}
class Probe extends ManagerToClientChannel
with HasCacheBlockAddress {
val p_type = UInt(width = co.probeTypeWidth)
val p_type = UInt(width = tlCoh.probeTypeWidth)
def is(t: UInt) = p_type === t
def makeRelease(
client_xact_id: UInt,
meta: ClientMetadata = co.clientMetadataOnFlush,
addr_beat: UInt = UInt(0),
data: UInt = UInt(0)): Release = {
Release(
voluntary = Bool(false),
r_type = co.getReleaseType(this, meta),
client_xact_id = client_xact_id,
addr_block = this.addr_block,
addr_beat = addr_beat,
data = data)
}
}
object Probe {
val co = new Probe().co
def apply(p_type: UInt, addr_block: UInt) = {
val prb = new Probe
prb.p_type := p_type
prb.addr_block := addr_block
prb
}
def onVoluntaryWriteback(meta: ManagerMetadata, addr_block: UInt): Probe = {
apply(co.getProbeType(M_FLUSH, meta), addr_block)
}
}
@ -305,31 +295,19 @@ class Release extends ClientToManagerChannel
with HasCacheBlockAddress
with HasClientTransactionId
with HasTileLinkData {
val r_type = UInt(width = co.releaseTypeWidth)
val r_type = UInt(width = tlCoh.releaseTypeWidth)
val voluntary = Bool()
// Helper funcs
def is(t: UInt) = r_type === t
def hasData(dummy: Int = 0) = co.releaseTypesWithData.contains(r_type)
def hasData(dummy: Int = 0) = tlCoh.releaseTypesWithData.contains(r_type)
//TODO: Assumes all releases write back full cache blocks:
def hasMultibeatData(dummy: Int = 0) = Bool(tlDataBeats > 1) && co.releaseTypesWithData.contains(r_type)
def hasMultibeatData(dummy: Int = 0) = Bool(tlDataBeats > 1) && tlCoh.releaseTypesWithData.contains(r_type)
def isVoluntary(dummy: Int = 0) = voluntary
def requiresAck(dummy: Int = 0) = !Bool(networkPreservesPointToPointOrdering)
def makeGrant(
manager_xact_id: UInt,
meta: ManagerMetadata = co.managerMetadataOnFlush): Grant = {
Grant(
g_type = Grant.voluntaryAck,
builtin_type = Bool(true), // Grant.voluntaryAck is built-in type
client_xact_id = this.client_xact_id,
manager_xact_id = manager_xact_id
)
}
def requiresAck(dummy: Int = 0) = !Bool(tlNetworkPreservesPointToPointOrdering)
}
object Release {
val co = new Release().co
def apply(
voluntary: Bool,
r_type: UInt,
@ -346,68 +324,52 @@ object Release {
rel.voluntary := voluntary
rel
}
def makeVoluntaryWriteback(
meta: ClientMetadata,
client_xact_id: UInt,
addr_block: UInt,
addr_beat: UInt = UInt(0),
data: UInt = UInt(0)): Release = {
Release(
voluntary = Bool(true),
r_type = co.getReleaseType(M_FLUSH, meta),
client_xact_id = client_xact_id,
addr_block = addr_block,
addr_beat = addr_beat,
data = data)
}
}
class Grant extends ManagerToClientChannel
with HasTileLinkData
with HasClientTransactionId
with HasManagerTransactionId {
val builtin_type = Bool()
val g_type = UInt(width = max(log2Up(Grant.nBuiltinGrantTypes), co.grantTypeWidth))
val is_builtin_type = Bool()
val g_type = UInt(width = tlGrantTypeBits)
// Helper funcs
def is(t: UInt) = g_type === t
def hasData(dummy: Int = 0): Bool = Mux(builtin_type,
def isBuiltInType(dummy: Int = 0): Bool = is_builtin_type
def is(t: UInt):Bool = g_type === t
def hasData(dummy: Int = 0): Bool = Mux(isBuiltInType(),
Grant.typesWithData.contains(g_type),
co.grantTypesWithData.contains(g_type))
tlCoh.grantTypesWithData.contains(g_type))
def hasMultibeatData(dummy: Int = 0): Bool =
Bool(tlDataBeats > 1) && Mux(builtin_type,
Bool(tlDataBeats > 1) && Mux(isBuiltInType(),
Grant.typesWithMultibeatData.contains(g_type),
co.grantTypesWithData.contains(g_type))
def isVoluntary(dummy: Int = 0): Bool = builtin_type && (g_type === Grant.voluntaryAck)
def requiresAck(dummy: Int = 0): Bool = !Bool(networkPreservesPointToPointOrdering) && !isVoluntary()
tlCoh.grantTypesWithData.contains(g_type))
def isVoluntary(dummy: Int = 0): Bool = isBuiltInType() && (g_type === Grant.voluntaryAckType)
def requiresAck(dummy: Int = 0): Bool = !Bool(tlNetworkPreservesPointToPointOrdering) && !isVoluntary()
def makeFinish(dummy: Int = 0): Finish = {
val f = new Finish
val f = Bundle(new Finish, { case TLManagerXactIdBits => tlManagerXactIdBits })
f.manager_xact_id := this.manager_xact_id
f
}
}
object Grant {
val nBuiltinGrantTypes = 5
//TODO Use Enum
def voluntaryAck = UInt(0)
def uncachedRead = UInt(1)
def uncachedReadBlock = UInt(2)
def uncachedWrite = UInt(3)
def uncachedAtomic = UInt(4)
def typesWithData = Vec(uncachedRead, uncachedReadBlock, uncachedAtomic)
def typesWithMultibeatData= Vec(uncachedReadBlock)
val nBuiltInTypes = 4
def voluntaryAckType = UInt("b00")
def ackType = UInt("b01")
def dataBeatType = UInt("b10")
def dataBlockType = UInt("b11")
def typesWithData = Vec(dataBlockType, dataBeatType)
def typesWithMultibeatData= Vec(dataBlockType)
def apply(
builtin_type: Bool,
is_builtin_type: Bool,
g_type: UInt,
client_xact_id: UInt,
manager_xact_id: UInt,
addr_beat: UInt = UInt(0),
data: UInt = UInt(0)): Grant = {
val gnt = new Grant
gnt.builtin_type := builtin_type
gnt.is_builtin_type := is_builtin_type
gnt.g_type := g_type
gnt.client_xact_id := client_xact_id
gnt.manager_xact_id := manager_xact_id
@ -415,23 +377,12 @@ object Grant {
gnt.data := data
gnt
}
def getGrantTypeForUncached(a: Acquire): UInt = {
MuxLookup(a.a_type, Grant.uncachedRead, Array(
Acquire.uncachedRead -> Grant.uncachedRead,
Acquire.uncachedReadBlock -> Grant.uncachedReadBlock,
Acquire.uncachedWrite -> Grant.uncachedWrite,
Acquire.uncachedWriteBlock -> Grant.uncachedWrite,
Acquire.uncachedAtomic -> Grant.uncachedAtomic
))
}
}
class Finish extends ClientToManagerChannel with HasManagerTransactionId
// Complete IO definitions for two types of TileLink clients
class UncachedTileLinkIO extends Bundle {
class UncachedTileLinkIO extends TLBundle {
val acquire = new DecoupledIO(new LogicalNetworkIO(new Acquire))
val grant = new DecoupledIO(new LogicalNetworkIO(new Grant)).flip
val finish = new DecoupledIO(new LogicalNetworkIO(new Finish))
@ -456,11 +407,17 @@ class TileLinkIOWrapper extends TLModule {
io.out.release.valid := Bool(false)
}
object TileLinkIOWrapper {
def apply[T <: Data](utl: UncachedTileLinkIO) = {
def apply(utl: UncachedTileLinkIO, p: Parameters): TileLinkIO = {
val conv = Module(new TileLinkIOWrapper)(p)
conv.io.in <> utl
conv.io.out
}
def apply(utl: UncachedTileLinkIO): TileLinkIO = {
val conv = Module(new TileLinkIOWrapper)
conv.io.in <> utl
conv.io.out
}
def apply(tl: TileLinkIO) = tl
}
abstract trait HasArbiterTypes {