Scalafmt & rename & update doc

This commit is contained in:
Hansung Kim
2023-11-10 14:58:16 -08:00
parent d51ce4cfa8
commit 5adf334af4

View File

@@ -1,4 +1,3 @@
//package freechips.rocketchip.rocket
package freechips.rocketchip.tilelink package freechips.rocketchip.tilelink
import chisel3._ import chisel3._
@@ -9,16 +8,12 @@ import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._ import freechips.rocketchip.tilelink._
import org.chipsalliance.cde.config.{Parameters, Field} import org.chipsalliance.cde.config.{Parameters, Field}
//Param and Key are used during SoC Generation
case class L1SystemParam(wordSize: Int = 16, busWidthInBytes: Int = 8) case class L1SystemParam(wordSize: Int = 16, busWidthInBytes: Int = 8)
case object L1SystemKey extends Field[Option[L1SystemConfig]](None /*default*/) case object L1SystemKey extends Field[Option[L1SystemConfig]](None /*default*/ )
case class L1SystemConfig( case class L1SystemConfig(
numBanks: Int, numBanks: Int,
wordSize: Int, //This is the read/write granularity of the L1 cache wordSize: Int, // This is the read/write granularity of the L1 cache
cacheLineSize: Int, cacheLineSize: Int,
coreTagWidth: Int, coreTagWidth: Int,
writeInfoReqQSize: Int, writeInfoReqQSize: Int,
@@ -32,7 +27,8 @@ case class L1SystemConfig(
} }
} }
object defaultL1SystemConfig extends L1SystemConfig( object defaultL1SystemConfig
extends L1SystemConfig(
numBanks = 4, numBanks = 4,
wordSize = 16, wordSize = 16,
cacheLineSize = 16, cacheLineSize = 16,
@@ -40,58 +36,46 @@ object defaultL1SystemConfig extends L1SystemConfig(
writeInfoReqQSize = 16, writeInfoReqQSize = 16,
mshrSize = 8, mshrSize = 8,
l2ReqSourceGenSize = 8, l2ReqSourceGenSize = 8,
uncachedAddrSets = Seq(AddressSet(0x2000000L, 0xFFL)), uncachedAddrSets = Seq(AddressSet(0x2000000L, 0xffL)),
icacheInstAddrSets = Seq(AddressSet(0x80000000L, 0xFFFFFFFL)) icacheInstAddrSets = Seq(AddressSet(0x80000000L, 0xfffffffL))
) ) {
require(mshrSize != l2ReqSourceGenSize)
}
class L1System (config:L1SystemConfig) (implicit p: Parameters) extends LazyModule { class L1System(config: L1SystemConfig)(implicit p: Parameters)
extends LazyModule {
// icache bank
val icache_bank = LazyModule(new VortexFatBank(config, 0, isICache = true))
//icache bank // dcache banks
val icache_bank = LazyModule(new VortexFatBank(config, 0, isICache=true))
//dcache banks
val dcache_banks = Seq.tabulate(config.numBanks) { bankId => val dcache_banks = Seq.tabulate(config.numBanks) { bankId =>
val bank = LazyModule(new VortexFatBank(config, bankId)) val bank = LazyModule(new VortexFatBank(config, bankId))
bank bank
} }
//passthrough // passthrough
val passThrough = LazyModule(new FatBankPassThrough(config)) val passThrough = LazyModule(new FatBankPassThrough(config))
//L1System exposes to upstream as a dmemXbar // L1System exposes to upstream as a dmemXbar
val dmemXbar = LazyModule(new TLXbar) val dmemXbar = LazyModule(new TLXbar)
dcache_banks.foreach { _.coalToVxCacheNode :=* dmemXbar.node} dcache_banks.foreach { _.coalToVxCacheNode :=* dmemXbar.node }
passThrough.coalToVxCacheNode :=* dmemXbar.node passThrough.coalToVxCacheNode :=* dmemXbar.node
icache_bank.coalToVxCacheNode :=* dmemXbar.node icache_bank.coalToVxCacheNode :=* dmemXbar.node
//L1System exposes to downstream as one tileLink Identity Node // L1System exposes to downstream as one tileLink Identity Node
val L1SystemToL2Node = TLIdentityNode() val L1SystemToL2Node = TLIdentityNode()
dcache_banks.foreach{ L1SystemToL2Node := _.vxCacheToL2Node} dcache_banks.foreach { L1SystemToL2Node := _.vxCacheToL2Node }
L1SystemToL2Node := passThrough.vxCacheToL2Node L1SystemToL2Node := passThrough.vxCacheToL2Node
L1SystemToL2Node := icache_bank.vxCacheToL2Node L1SystemToL2Node := icache_bank.vxCacheToL2Node
lazy val module = new LazyModuleImp(this) lazy val module = new LazyModuleImp(this)
} }
// TODO: Make the FatBank Pass Through a Blocking Module
//To-Do class FatBankPassThrough(config: L1SystemConfig)(implicit p: Parameters)
//Make the FatBank Pass Through a Blocking Module extends LazyModule {
class FatBankPassThrough(config:L1SystemConfig) (implicit p: Parameters) extends LazyModule { // Slave node to upstream
val managerParam = Seq(
val clientParam = Seq(TLMasterPortParameters.v1( TLSlavePortParameters.v1(
clients = Seq(
TLMasterParameters.v1(
name = "VortexFatBank",
sourceId = IdRange(0, 1 << (log2Ceil(config.l2ReqSourceGenSize)+5) ),
supportsProbe = TransferSizes(1, config.wordSize),
supportsGet = TransferSizes(1, config.wordSize),
supportsPutFull = TransferSizes(1, config.wordSize),
supportsPutPartial = TransferSizes(1, config.wordSize)
)
)
))
val managerParam = Seq(TLSlavePortParameters.v1(
beatBytes = config.wordSize, beatBytes = config.wordSize,
managers = Seq( managers = Seq(
TLSlaveParameters.v1( TLSlaveParameters.v1(
@@ -104,14 +88,31 @@ class FatBankPassThrough(config:L1SystemConfig) (implicit p: Parameters) extends
fifoId = Some(0) fifoId = Some(0)
) )
) )
)) )
)
// Master node to downstream
val clientParam = Seq(
TLMasterPortParameters.v1(
clients = Seq(
TLMasterParameters.v1(
name = "VortexFatBank",
sourceId = IdRange(0, 1 << (log2Ceil(config.l2ReqSourceGenSize) + 5)),
supportsProbe = TransferSizes(1, config.wordSize),
supportsGet = TransferSizes(1, config.wordSize),
supportsPutFull = TransferSizes(1, config.wordSize),
supportsPutPartial = TransferSizes(1, config.wordSize)
)
)
)
)
val coalToVxCacheNode = TLManagerNode(managerParam) val coalToVxCacheNode = TLManagerNode(managerParam)
val vxCacheFetchNode = TLClientNode(clientParam) val vxCacheFetchNode = TLClientNode(clientParam)
val vxCacheToL2Node = TLIdentityNode() val vxCacheToL2Node = TLIdentityNode()
vxCacheToL2Node := TLWidthWidget(config.cacheLineSize) := vxCacheFetchNode vxCacheToL2Node := TLWidthWidget(config.cacheLineSize) := vxCacheFetchNode
//the implementation to make everything a pass through // the implementation to make everything a pass through
lazy val module = new LazyModuleImp(this) { lazy val module = new LazyModuleImp(this) {
val (upstream, _) = coalToVxCacheNode.in(0) val (upstream, _) = coalToVxCacheNode.in(0)
val (downstream, _) = vxCacheFetchNode.out(0) val (downstream, _) = vxCacheFetchNode.out(0)
@@ -119,52 +120,38 @@ class FatBankPassThrough(config:L1SystemConfig) (implicit p: Parameters) extends
downstream.a <> upstream.a downstream.a <> upstream.a
upstream.d <> downstream.d upstream.d <> downstream.d
} }
} }
class VortexFatBank(
config: L1SystemConfig,
bankId: Int,
class VortexFatBank (config: L1SystemConfig, bankId: Int, isICache: Boolean = false) isICache: Boolean = false
(implicit p: Parameters) extends LazyModule { )(implicit p: Parameters)
extends LazyModule {
// Generate AddressSet by excluding Addr we don't want
//Generate AddressSet by excluding Addr we don't want
def generateAddressSets(): Seq[AddressSet] = { def generateAddressSets(): Seq[AddressSet] = {
if (isICache) {
if (isICache){
config.icacheInstAddrSets config.icacheInstAddrSets
//Seq(AddressSet(0x00000000L, 0xFFFFFFFFL)) // Seq(AddressSet(0x00000000L, 0xFFFFFFFFL))
} else { } else {
//suppose have 4 bank // suppose have 4 bank
//base for bank 1: ...000000|01|0000 // base for bank 1: ...000000|01|0000
//mask for bank 1; 111111|00|1111 // mask for bank 1; 111111|00|1111
val mask = 0xFFFFFFFFL ^ ((config.numBanks-1)*config.wordSize) val mask = 0xffffffffL ^ ((config.numBanks - 1) * config.wordSize)
val base = 0x00000000L | (bankId * config.wordSize) val base = 0x00000000L | (bankId * config.wordSize)
val excludeSets = (config.uncachedAddrSets ++ config.icacheInstAddrSets) val excludeSets = (config.uncachedAddrSets ++ config.icacheInstAddrSets)
var remainingSets: Seq[AddressSet] = Seq(AddressSet(base, mask)) var remainingSets: Seq[AddressSet] = Seq(AddressSet(base, mask))
for(excludeSet <- excludeSets) { for (excludeSet <- excludeSets) {
remainingSets = remainingSets.flatMap(_.subtract(excludeSet)) remainingSets = remainingSets.flatMap(_.subtract(excludeSet))
} }
remainingSets remainingSets
} }
} }
val clientParam = Seq(TLMasterPortParameters.v1( // Slave node to upstream
clients = Seq( val managerParam = Seq(
TLMasterParameters.v1( TLSlavePortParameters.v1(
name = "VortexFatBank",
sourceId = IdRange(0, config.l2ReqSourceGenSize),
supportsProbe = TransferSizes(1, config.wordSize),
supportsGet = TransferSizes(1, config.wordSize),
supportsPutFull = TransferSizes(1, config.wordSize),
supportsPutPartial = TransferSizes(1, config.wordSize)
)
)
))
val managerParam = Seq(TLSlavePortParameters.v1(
beatBytes = config.wordSize, beatBytes = config.wordSize,
managers = Seq( managers = Seq(
TLSlaveParameters.v1( TLSlaveParameters.v1(
@@ -177,44 +164,59 @@ class VortexFatBank (config: L1SystemConfig, bankId: Int, isICache: Boolean = fa
fifoId = Some(0) fifoId = Some(0)
) )
) )
)) )
)
// Master node to downstream
val clientParam = Seq(
TLMasterPortParameters.v1(
clients = Seq(
TLMasterParameters.v1(
name = "VortexFatBank",
sourceId = IdRange(0, config.l2ReqSourceGenSize),
supportsProbe = TransferSizes(1, config.wordSize),
supportsGet = TransferSizes(1, config.wordSize),
supportsPutFull = TransferSizes(1, config.wordSize),
supportsPutPartial = TransferSizes(1, config.wordSize)
)
)
)
)
val coalToVxCacheNode = TLManagerNode(managerParam) val coalToVxCacheNode = TLManagerNode(managerParam)
val vxCacheToL2Node = TLIdentityNode() val vxCacheToL2Node = TLIdentityNode()
val vxCacheFetchNode = TLClientNode(clientParam) val vxCacheFetchNode = TLClientNode(clientParam)
//We need this widthWidget here, because whenever the fatBank is performing // We need this widthWidget here, because whenever the fatBank is performing
//read and write to Mem, it must have the illusion that dataWidth is as big as // read and write to Mem, it must have the illusion that dataWidth is as big as
//as its cacheline size // as its cacheline size
vxCacheToL2Node := TLWidthWidget(config.cacheLineSize) := vxCacheFetchNode vxCacheToL2Node := TLWidthWidget(config.cacheLineSize) := vxCacheFetchNode
lazy val module = new VortexFatBankImp(this, config); lazy val module = new VortexFatBankImp(this, config);
} }
class VortexFatBankImp ( class VortexFatBankImp(
outer: VortexFatBank, outer: VortexFatBank,
config: L1SystemConfig config: L1SystemConfig
) extends LazyModuleImp(outer) { ) extends LazyModuleImp(outer) {
val vxCache = Module(
val vxCache = Module(new VX_cache( new VX_cache(
WORD_SIZE=config.wordSize, WORD_SIZE = config.wordSize,
CACHE_LINE_SIZE=config.cacheLineSize, CACHE_LINE_SIZE = config.cacheLineSize,
CORE_TAG_WIDTH= config.coreTagPlusSizeWidth, CORE_TAG_WIDTH = config.coreTagPlusSizeWidth,
MSHR_SIZE= config.mshrSize MSHR_SIZE = config.mshrSize
) )
); );
vxCache.io.clk := clock vxCache.io.clk := clock
vxCache.io.reset := reset vxCache.io.reset := reset
val writeReqCount = RegInit(UInt(32.W), 0.U) val writeReqCount = RegInit(UInt(32.W), 0.U)
val writeInputFire = Wire(Bool()) val writeInputFire = Wire(Bool())
val writeOutputFire = Wire(Bool()) val writeOutputFire = Wire(Bool())
when(writeInputFire && ~writeOutputFire) {
when(writeInputFire && ~writeOutputFire){
writeReqCount := writeReqCount + 1.U writeReqCount := writeReqCount + 1.U
}.elsewhen(~writeInputFire && writeOutputFire){ }.elsewhen(~writeInputFire && writeOutputFire) {
writeReqCount := writeReqCount - 1.U writeReqCount := writeReqCount - 1.U
} }
@@ -222,8 +224,6 @@ class VortexFatBankImp (
dontTouch(writeOutputFire) dontTouch(writeOutputFire)
dontTouch(writeReqCount) dontTouch(writeReqCount)
class WriteReqInfo extends Bundle { class WriteReqInfo extends Bundle {
val id = UInt(32.W) val id = UInt(32.W)
val size = UInt(32.W) val size = UInt(32.W)
@@ -234,7 +234,14 @@ class VortexFatBankImp (
val id = UInt(config.coreTagWidth.W) val id = UInt(config.coreTagWidth.W)
} }
val rcvWriteReqInfo = Module(new Queue((new WriteReqInfo).cloneType, config.writeInfoReqQSize, true, false)) val rcvWriteReqInfo = Module(
new Queue(
(new WriteReqInfo).cloneType,
config.writeInfoReqQSize,
true,
false
)
)
val readReqInfo = Wire(new ReadReqInfo(config)) val readReqInfo = Wire(new ReadReqInfo(config))
// Translate TL request from Coalescer to requests for VX_cache // Translate TL request from Coalescer to requests for VX_cache
@@ -243,46 +250,50 @@ class VortexFatBankImp (
// coal -> vxCache request on channel A // coal -> vxCache request on channel A
val coalToBankA = coalToBankBundle.a; val coalToBankA = coalToBankBundle.a;
coalToBankA.ready := vxCache.io.core_req_ready && rcvWriteReqInfo.io.enq.ready //not optimal coalToBankA.ready := vxCache.io.core_req_ready && rcvWriteReqInfo.io.enq.ready // not optimal
vxCache.io.core_req_valid := coalToBankA.valid vxCache.io.core_req_valid := coalToBankA.valid
// read = 0, write = 1 // read = 0, write = 1
vxCache.io.core_req_rw := !(coalToBankA.bits.opcode === TLMessages.Get) vxCache.io.core_req_rw := !(coalToBankA.bits.opcode === TLMessages.Get)
//4 is also hardcoded, it should be log2WordSize // 4 is also hardcoded, it should be log2WordSize
vxCache.io.core_req_addr := coalToBankA.bits.address(31, log2Ceil(config.wordSize)) vxCache.io.core_req_addr := coalToBankA.bits.address(
31,
log2Ceil(config.wordSize)
)
vxCache.io.core_req_byteen := coalToBankA.bits.mask vxCache.io.core_req_byteen := coalToBankA.bits.mask
vxCache.io.core_req_data := coalToBankA.bits.data vxCache.io.core_req_data := coalToBankA.bits.data
//combine size and tag field into one big wire, to put into vxCache.io.core_req_tag // combine size and tag field into one big wire, to put into vxCache.io.core_req_tag
readReqInfo.id := coalToBankA.bits.source readReqInfo.id := coalToBankA.bits.source
readReqInfo.size := coalToBankA.bits.size readReqInfo.size := coalToBankA.bits.size
vxCache.io.core_req_tag := readReqInfo.asTypeOf(vxCache.io.core_req_tag) vxCache.io.core_req_tag := readReqInfo.asTypeOf(vxCache.io.core_req_tag)
writeInputFire := vxCache.io.core_req_rw && coalToBankA.fire writeInputFire := vxCache.io.core_req_rw && coalToBankA.fire
// we ignore param, size, corrupt fields // ignore param, size, corrupt fields
// vxCache -> coal response on channel D // vxCache -> coal response on channel D
// ok ... this part is a little tricky, the downstream coalescer requires the L1 cache // ok ... this part is a little tricky, the downstream coalescer requires
// to send ack and dataAck, this is how coalescer knows when an inflight ID has retired // the L1 cache to send ack and dataAck, this is how coalescer knows when
// if we don't send ack, the coalescer will run out of IDs, and can't generate new request // an inflight ID has retired if we don't send ack, the coalescer will run
// out of IDs, and can't generate new request
// for read request, we send AckData when the FatBank has a valid output // for read request, we send AckData when the FatBank has a valid output
// for write request, we can ack whenever we have a valid entry in rcvWriteReqInfo Queue //
// for write request, we can ack whenever we have a valid entry in
//I think this just shows the flaws of Tilelink. CPU never waits for an Ack upon regular write request // rcvWriteReqInfo Queue
//the Core should unconditionally move forward after every regular write request
val coalToBankD = coalToBankBundle.d; val coalToBankD = coalToBankBundle.d;
// FIXME: currently assuming below buffer is never full
//<FIXME> currently assuming below buffer is never full
rcvWriteReqInfo.io.enq.valid := !(coalToBankA.bits.opcode === TLMessages.Get) && coalToBankA.valid && coalToBankA.ready rcvWriteReqInfo.io.enq.valid := !(coalToBankA.bits.opcode === TLMessages.Get) && coalToBankA.valid && coalToBankA.ready
rcvWriteReqInfo.io.enq.bits.id := coalToBankA.bits.source rcvWriteReqInfo.io.enq.bits.id := coalToBankA.bits.source
rcvWriteReqInfo.io.enq.bits.size := coalToBankA.bits.size rcvWriteReqInfo.io.enq.bits.size := coalToBankA.bits.size
//prioritize Ack for Read, so we only deque from writeReqInfo, if we don't have a readReq we need to ack // prioritize Ack for Read, so we only deque from writeReqInfo, if we don't
//vxCache.io.core_rsp_valid means readDataAck // have a readReq we need to ack
//
// vxCache.io.core_rsp_valid means readDataAck
rcvWriteReqInfo.io.deq.ready := coalToBankD.ready && ~vxCache.io.core_rsp_valid rcvWriteReqInfo.io.deq.ready := coalToBankD.ready && ~vxCache.io.core_rsp_valid
vxCache.io.core_rsp_ready := coalToBankD.ready vxCache.io.core_rsp_ready := coalToBankD.ready
@@ -310,113 +321,98 @@ class VortexFatBankImp (
coalToBankD.bits.sink := 0.U coalToBankD.bits.sink := 0.U
coalToBankD.bits.denied := false.B coalToBankD.bits.denied := false.B
coalToBankD.bits.corrupt := false.B coalToBankD.bits.corrupt := false.B
coalToBankD.bits.data := vxCache.io.core_rsp_data coalToBankD.bits.data := vxCache.io.core_rsp_data
} }
// Since Vortex L1 is a write-through cache, it doesn't bookkeep writes and
//Using Hansung's Source Generator // therefore doesn't allocate a new UUID for write requests. We use a
//Why do we need to do this, what is the issue ? // separate source ID allocator to solve this.
//Tilelink requires all inflight Read and Write Request to have a unique source_ID val sourceGen = Module(
//vx_cache can indeed guarantee that all active read operation has unique ID new NewSourceGenerator(
//However, since the cache is write_through, so it can't ensure unique ID for write operation
//Therefore, we need our own internal source_ID generator for all write operation
val sourceGen = Module( new NewSourceGenerator(
log2Ceil(config.l2ReqSourceGenSize), log2Ceil(config.l2ReqSourceGenSize),
metadata = Some(UInt(32.W)), metadata = Some(UInt(32.W)),
ignoreInUse = false) ignoreInUse = false
)
) )
// Translate VX_cache mem request to a TL request to be sent to L2 // Translate VX_cache mem request to a TL request to be sent to L2
def VXReq2TLReq = { def VXReq2TLReq = {
val (vxCacheToL2Bundle, _) = outer.vxCacheFetchNode.out.head val (tlOutToL2, _) = outer.vxCacheFetchNode.out.head
// vxCache -> L2 request on channel A
val vxCacheToL2A = vxCacheToL2Bundle.a;
// vxCache -> downstream L2 request
vxCache.io.mem_req_ready := tlOutToL2.a.ready && sourceGen.io.id.valid
tlOutToL2.a.valid := vxCache.io.mem_req_valid && sourceGen.io.id.valid
//Read Operation is ready as long as downstream L2 is ready sourceGen.io.gen := tlOutToL2.a.fire
sourceGen.io.meta := vxCache.io.mem_req_tag // save the old read id
vxCache.io.mem_req_ready := vxCacheToL2A.ready && sourceGen.io.id.valid writeOutputFire := tlOutToL2.a.fire && vxCache.io.mem_req_rw
vxCacheToL2A.valid := vxCache.io.mem_req_valid && sourceGen.io.id.valid tlOutToL2.a.bits.opcode := Mux(
sourceGen.io.gen := vxCacheToL2A.fire
writeOutputFire := vxCacheToL2A.fire && vxCache.io.mem_req_rw
vxCacheToL2A.bits.opcode := Mux(
vxCache.io.mem_req_rw, vxCache.io.mem_req_rw,
Mux(vxCache.io.mem_req_byteen.andR, TLMessages.PutFullData, TLMessages.PutPartialData), Mux(
vxCache.io.mem_req_byteen.andR,
TLMessages.PutFullData,
TLMessages.PutPartialData
),
TLMessages.Get TLMessages.Get
) )
vxCacheToL2A.bits.address := Cat(vxCache.io.mem_req_addr, 0.U(4.W)) tlOutToL2.a.bits.address := Cat(vxCache.io.mem_req_addr, 0.U(4.W))
tlOutToL2.a.bits.mask := Mux(
vxCacheToL2A.bits.mask := Mux(
vxCache.io.mem_req_rw, vxCache.io.mem_req_rw,
vxCache.io.mem_req_byteen, vxCache.io.mem_req_byteen,
0xFFFF.U 0xffff.U
) )
tlOutToL2.a.bits.data := vxCache.io.mem_req_data
tlOutToL2.a.bits.source := sourceGen.io.id.bits
// ignore param, size, corrupt fields
tlOutToL2.a.bits.param := 0.U
tlOutToL2.a.bits.size := 4.U // FIXME: hardcoded
tlOutToL2.a.bits.corrupt := false.B
// downstream L2 -> vxCache response
tlOutToL2.d.ready := vxCache.io.mem_rsp_ready
vxCacheToL2A.bits.data := vxCache.io.mem_req_data vxCache.io.mem_rsp_valid :=
tlOutToL2.d.valid && (tlOutToL2.d.bits.opcode === TLMessages.AccessAckData)
vxCacheToL2A.bits.source := sourceGen.io.id.bits
sourceGen.io.meta := vxCache.io.mem_req_tag //save the old read id
vxCacheToL2A.bits.param := 0.U
vxCacheToL2A.bits.size := 4.U
vxCacheToL2A.bits.corrupt := false.B
// we ignore param, size, corrupt fields
// L2 -> vxCache response on channel D
val vxCacheToL2D = vxCacheToL2Bundle.d;
vxCacheToL2D.ready := vxCache.io.mem_rsp_ready
vxCache.io.mem_rsp_valid := vxCacheToL2D.valid && vxCacheToL2D.bits.opcode === TLMessages.AccessAckData
vxCache.io.mem_rsp_tag := sourceGen.io.peek vxCache.io.mem_rsp_tag := sourceGen.io.peek
vxCache.io.mem_rsp_data := vxCacheToL2D.bits.data vxCache.io.mem_rsp_data := tlOutToL2.d.bits.data
// all ids needs to be reclaimed
sourceGen.io.reclaim.valid := vxCacheToL2D.fire
sourceGen.io.reclaim.bits := vxCacheToL2D.bits.source
sourceGen.io.reclaim.valid := tlOutToL2.d.fire
sourceGen.io.reclaim.bits := tlOutToL2.d.bits.source
} }
TLReq2VXReq TLReq2VXReq
VXReq2TLReq VXReq2TLReq
} }
class VX_cache ( class VX_cache(
CACHE_ID: Int = 0, CACHE_ID: Int = 0,
CACHE_SIZE: Int = 16384/4, //<FIXME, divided by 4 for faster simulation CACHE_SIZE: Int = 16384 / 4, // <FIXME, divided by 4 for faster simulation
CACHE_LINE_SIZE: Int = 16, CACHE_LINE_SIZE: Int = 16,
NUM_PORTS: Int = 1, NUM_PORTS: Int = 1,
WORD_SIZE: Int = 16, // hack - one "word" is enough to satisfy all 4 warps after decoalescing. WORD_SIZE: Int =
16, // hack - one "word" is enough to satisfy all 4 warps after decoalescing.
CREQ_SIZE: Int = 0, CREQ_SIZE: Int = 0,
CRSQ_SIZE: Int = 2, CRSQ_SIZE: Int = 2,
MSHR_SIZE: Int = 8, MSHR_SIZE: Int = 8,
MRSQ_SIZE: Int = 0, MRSQ_SIZE: Int = 0,
MREQ_SIZE: Int = 4, MREQ_SIZE: Int = 4,
WRITE_ENABLE: Int = 1, WRITE_ENABLE: Int = 1,
CORE_TAG_WIDTH: Int = 10, // source ID ranges from 0 to 1 << 10, we need to allocate upper bits to save size CORE_TAG_WIDTH: Int =
CORE_TAG_ID_BITS: Int = 5, // no idea what this is, just match it with default L1 dcache 10, // source ID ranges from 0 to 1 << 10, we need to allocate upper bits to save size
CORE_TAG_ID_BITS: Int =
5, // no idea what this is, just match it with default L1 dcache
BANK_ADDR_OFFSET: Int = 0, BANK_ADDR_OFFSET: Int = 0,
NC_ENABLE: Int = 0, //NC_ENABLE=1 means the cache becomes a passthrough NC_ENABLE: Int = 0, // NC_ENABLE=1 means the cache becomes a passthrough
WORD_ADDR_WIDTH: Int = 28, // 16 byte "word" = 4 bits WORD_ADDR_WIDTH: Int = 28, // 16 byte "word" = 4 bits
MEM_TAG_WIDTH: Int = 14, // Elaborated value is also completely different from (32 - log2Ceil(CACHE_LINE_SIZE)). This should match with sourceIds on client node associated with this cache MEM_TAG_WIDTH: Int =
14, // Elaborated value is also completely different from (32 - log2Ceil(CACHE_LINE_SIZE)). This should match with sourceIds on client node associated with this cache
MEM_ADDR_WIDTH: Int = 28 // 16 byte cache line = 4 bits MEM_ADDR_WIDTH: Int = 28 // 16 byte cache line = 4 bits
) extends BlackBox ( ) extends BlackBox(
Map( Map(
"CACHE_ID" -> CACHE_ID, "CACHE_ID" -> CACHE_ID,
"NUM_REQS" -> 1, //Force NUM_REQS to be 1, we use their Cache as our individual Bank "NUM_REQS" -> 1, // Force NUM_REQS to be 1, we use their Cache as our individual Bank
"CACHE_SIZE" -> CACHE_SIZE, "CACHE_SIZE" -> CACHE_SIZE,
"CACHE_LINE_SIZE" -> CACHE_LINE_SIZE, "CACHE_LINE_SIZE" -> CACHE_LINE_SIZE,
"NUM_PORTS" -> NUM_PORTS, "NUM_PORTS" -> NUM_PORTS,
@@ -431,9 +427,10 @@ class VX_cache (
"CORE_TAG_ID_BITS" -> CORE_TAG_ID_BITS, "CORE_TAG_ID_BITS" -> CORE_TAG_ID_BITS,
"MEM_TAG_WIDTH" -> MEM_TAG_WIDTH, "MEM_TAG_WIDTH" -> MEM_TAG_WIDTH,
"BANK_ADDR_OFFSET" -> BANK_ADDR_OFFSET, "BANK_ADDR_OFFSET" -> BANK_ADDR_OFFSET,
"NC_ENABLE" -> NC_ENABLE, "NC_ENABLE" -> NC_ENABLE
) )
) with HasBlackBoxResource { )
with HasBlackBoxResource {
val io = IO(new Bundle { val io = IO(new Bundle {
val clk = Input(Clock()) val clk = Input(Clock())
@@ -451,7 +448,8 @@ class VX_cache (
val core_req_ready = Output(Bool()) val core_req_ready = Output(Bool())
val core_rsp_valid = Output(Bool()) // 1 bit wide val core_rsp_valid = Output(Bool()) // 1 bit wide
val core_rsp_tmask = Output(Bool()) // 1 bit wide, probably can ignore (check waveform) val core_rsp_tmask =
Output(Bool()) // 1 bit wide, probably can ignore (check waveform)
val core_rsp_data = Output(UInt((WORD_SIZE * 8).W)) val core_rsp_data = Output(UInt((WORD_SIZE * 8).W))
val core_rsp_tag = Output(UInt(CORE_TAG_WIDTH.W)) val core_rsp_tag = Output(UInt(CORE_TAG_WIDTH.W))
val core_rsp_ready = Input(Bool()) val core_rsp_ready = Input(Bool())
@@ -471,7 +469,6 @@ class VX_cache (
val mem_rsp_ready = Output(Bool()) val mem_rsp_ready = Output(Bool())
}) })
addResource("/vsrc/vortex/hw/rtl/VX_dispatch.sv") addResource("/vsrc/vortex/hw/rtl/VX_dispatch.sv")
addResource("/vsrc/vortex/hw/rtl/VX_issue.sv") addResource("/vsrc/vortex/hw/rtl/VX_issue.sv")
addResource("/vsrc/vortex/hw/rtl/cache/VX_cache_define.vh") addResource("/vsrc/vortex/hw/rtl/cache/VX_cache_define.vh")
@@ -588,7 +585,7 @@ class VX_cache (
addResource("/vsrc/vortex/hw/rtl/interfaces/VX_perf_tex_if.sv") addResource("/vsrc/vortex/hw/rtl/interfaces/VX_perf_tex_if.sv")
addResource("/vsrc/vortex/hw/rtl/interfaces/VX_mem_req_if.sv") addResource("/vsrc/vortex/hw/rtl/interfaces/VX_mem_req_if.sv")
addResource("/vsrc/vortex/hw/rtl/interfaces/VX_fpu_req_if.sv") addResource("/vsrc/vortex/hw/rtl/interfaces/VX_fpu_req_if.sv")
//addResource("/vsrc/vortex/hw/rtl/cache/VX_shared_mem.sv") // addResource("/vsrc/vortex/hw/rtl/cache/VX_shared_mem.sv")
addResource("/vsrc/vortex/hw/rtl/cache/VX_core_rsp_merge.sv") addResource("/vsrc/vortex/hw/rtl/cache/VX_core_rsp_merge.sv")
addResource("/vsrc/vortex/hw/rtl/cache/VX_tag_access.sv") addResource("/vsrc/vortex/hw/rtl/cache/VX_tag_access.sv")
addResource("/vsrc/vortex/hw/rtl/cache/VX_core_req_bank_sel.sv") addResource("/vsrc/vortex/hw/rtl/cache/VX_core_req_bank_sel.sv")
@@ -601,11 +598,8 @@ class VX_cache (
} }
// <FIXME> Delete the following NewSourceGenerator when merging with origin/graphics
// we should just use the one in coalescing.scala written by hansung
//<FIXME> Delete the following NewSourceGenerator when merging with origin/graphics
//we should just use the one in coalescing.scala written by hansung
class NewSourceGenerator[T <: Data]( class NewSourceGenerator[T <: Data](
sourceWidth: Int, sourceWidth: Int,
@@ -663,32 +657,40 @@ class NewSourceGenerator[T <: Data](
io.id.bits := lowestFree io.id.bits := lowestFree
when(io.gen && io.id.valid /* fire */ ) { when(io.gen && io.id.valid /* fire */ ) {
occupancyTable(io.id.bits).id.valid := true.B // mark in use occupancyTable(io.id.bits).id.valid := true.B // mark in use
occupancyTable(io.id.bits).age := 0.U // reset age upon issuing, double safety occupancyTable(
io.id.bits
).age := 0.U // reset age upon issuing, double safety
if (metadata.isDefined) { if (metadata.isDefined) {
occupancyTable(io.id.bits).meta := io.meta occupancyTable(io.id.bits).meta := io.meta
} }
} }
// Increase age of all inflight IDs by 1, except for the one being reclaimed // Increase age of all inflight IDs by 1, except for the one being reclaimed
for(i <- 0 until numSourceId) { for (i <- 0 until numSourceId) {
when(occupancyTable(i).id.valid && (i.U =/= io.reclaim.bits || !io.reclaim.valid)) { when(
occupancyTable(
i
).id.valid && (i.U =/= io.reclaim.bits || !io.reclaim.valid)
) {
occupancyTable(i).age := occupancyTable(i).age + 1.U occupancyTable(i).age := occupancyTable(i).age + 1.U
} }
} }
when(io.reclaim.valid) { when(io.reclaim.valid) {
assert(occupancyTable(io.reclaim.bits).id.valid === true.B, "tried to reclaim a non-used id") assert(
occupancyTable(io.reclaim.bits).id.valid === true.B,
"tried to reclaim a non-used id"
)
occupancyTable(io.reclaim.bits).id.valid := false.B // mark freed occupancyTable(io.reclaim.bits).id.valid := false.B // mark freed
occupancyTable(io.reclaim.bits).age := 0.U occupancyTable(io.reclaim.bits).age := 0.U
} }
io.peek := { io.peek := {
if (metadata.isDefined) occupancyTable(io.reclaim.bits).meta else 0.U if (metadata.isDefined) occupancyTable(io.reclaim.bits).meta else 0.U
} }
when(io.gen && io.id.valid) { when(io.gen && io.id.valid) {
when (!io.reclaim.valid) { when(!io.reclaim.valid) {
assert(outstanding < (1 << sourceWidth).U) assert(outstanding < (1 << sourceWidth).U)
outstanding := outstanding + 1.U outstanding := outstanding + 1.U
} }
@@ -699,7 +701,9 @@ class NewSourceGenerator[T <: Data](
// Debugging wires // Debugging wires
val ages = VecInit((0 until numSourceId).map(i => occupancyTable(i).age)) val ages = VecInit((0 until numSourceId).map(i => occupancyTable(i).age))
val oldestIndex = PriorityEncoder(ages.map(a => a === ages.reduce((x, y) => Mux(x > y, x, y)))) val oldestIndex = PriorityEncoder(
ages.map(a => a === ages.reduce((x, y) => Mux(x > y, x, y)))
)
val oldestIdInflight = Wire(UInt(sourceWidth.W)) val oldestIdInflight = Wire(UInt(sourceWidth.W))
val oldestMetadata = Wire(getMetadataType) val oldestMetadata = Wire(getMetadataType)
val oldestAge = Wire(UInt(32.W)) val oldestAge = Wire(UInt(32.W))
@@ -707,7 +711,10 @@ class NewSourceGenerator[T <: Data](
oldestIdInflight := oldestIndex oldestIdInflight := oldestIndex
oldestMetadata := occupancyTable(oldestIndex).meta oldestMetadata := occupancyTable(oldestIndex).meta
oldestAge := occupancyTable(oldestIndex).age oldestAge := occupancyTable(oldestIndex).age
assert(oldestAge <= 2000.U, "One id in the SourceGen is not released for long time, potential bug !") assert(
oldestAge <= 2000.U,
"One id in the SourceGen is not released for long time, potential bug !"
)
dontTouch(oldestIdInflight) dontTouch(oldestIdInflight)
dontTouch(oldestMetadata) dontTouch(oldestMetadata)