From d4da0b9123fc79e1f2a207198e3a8c20b0fa070e Mon Sep 17 00:00:00 2001 From: BigWhiteDog Date: Wed, 20 Jan 2021 15:47:44 +0800 Subject: [PATCH] add amo test --- src/test/scala/cache/L1DTest/CoreAgent.scala | 67 ++++++++++++++++++- .../scala/cache/L1DTest/CoreTransatcion.scala | 35 ++++++++++ src/test/scala/cache/L1DTest/L1DTest.scala | 57 +++++++++++++++- src/test/scala/cache/TLCTest/TLCAgent.scala | 16 +++++ 4 files changed, 171 insertions(+), 4 deletions(-) diff --git a/src/test/scala/cache/L1DTest/CoreAgent.scala b/src/test/scala/cache/L1DTest/CoreAgent.scala index ab6e862c3..8a9c23710 100644 --- a/src/test/scala/cache/L1DTest/CoreAgent.scala +++ b/src/test/scala/cache/L1DTest/CoreAgent.scala @@ -8,18 +8,24 @@ import scala.collection.mutable.{ArrayBuffer, ListBuffer} class CoreAgent(ID: Int, name: String, addrStateMap: mutable.Map[BigInt, AddrState], serialList: ArrayBuffer[(Int, TLCTrans)] , scoreboard: mutable.Map[BigInt, ScoreboardData], portNum: Int = 2) - (implicit p: Parameters) extends TLCAgent(ID, name, addrStateMap, serialList, scoreboard) { + (implicit p: Parameters) extends TLCAgent(ID, name, addrStateMap, serialList, scoreboard) with LitMemOp { private val loadPortsReqMessage = ArrayBuffer.fill[Option[LitDCacheWordReq]](portNum)(None) private val s0_loadTrans = ArrayBuffer.fill[Option[DCacheLoadCallerTrans]](portNum)(None) private val s1_loadTrans = ArrayBuffer.fill[Option[DCacheLoadCallerTrans]](portNum)(None) private val s2_loadTrans = ArrayBuffer.fill[Option[DCacheLoadCallerTrans]](portNum)(None) private var storePortReqMessage: Option[LitDCacheLineReq] = None + private var amoPortReqMessage: Option[LitDCacheWordReq] = None val outerLoad: ListBuffer[DCacheLoadCallerTrans] = ListBuffer() val outerStore: ListBuffer[DCacheStoreCallerTrans] = ListBuffer() + val outerAMO: ListBuffer[DCacheAMOCallerTrans] = ListBuffer() + + private val maxStoreId = 255 + private val maxAMOId = 0 private val lsqWaiting: mutable.Queue[DCacheLoadCallerTrans] = mutable.Queue[DCacheLoadCallerTrans]() private val storeIdMap: mutable.Map[BigInt, DCacheStoreCallerTrans] = mutable.Map[BigInt, DCacheStoreCallerTrans]() + private val amoIdMap: mutable.Map[BigInt, DCacheAMOCallerTrans] = mutable.Map[BigInt, DCacheAMOCallerTrans]() def issueLoadReq(): Unit = { for (i <- 0 until portNum) { @@ -108,7 +114,7 @@ class CoreAgent(ID: Int, name: String, addrStateMap: mutable.Map[BigInt, AddrSta if (storePortReqMessage.isEmpty) { val nextStore = outerStore.find(s => !s.reqIssued.getOrElse(true)) if (nextStore.isDefined) { - val allocId = (0 to 255).find(i => !storeIdMap.contains(BigInt(i))) + val allocId = (0 to maxStoreId).find(i => !storeIdMap.contains(BigInt(i))) if (allocId.isDefined) { //alloc & issue storePortReqMessage = Some(nextStore.get.issueReq(BigInt(allocId.get))) @@ -141,6 +147,42 @@ class CoreAgent(ID: Int, name: String, addrStateMap: mutable.Map[BigInt, AddrSta insertMaskedWrite(storeReq.addr, storeReq.data, storeReq.mask) } + def issueAMOReq(): Unit = { + if (amoPortReqMessage.isEmpty) { + val nextAMO = outerAMO.find(a => !a.reqIssued.getOrElse(true)) + if (nextAMO.isDefined) { + val allocId = (0 to maxAMOId).find(i => !amoIdMap.contains(BigInt(i))) + if (allocId.isDefined) { + val aid = allocId.get + //alloc & issue + amoPortReqMessage = Some(nextAMO.get.issueReq(BigInt(aid))) + amoIdMap(BigInt(aid)) + } + } + } + } + + def peekAMOReq(): Option[LitDCacheWordReq] = { + amoPortReqMessage + } + + def fireAMOReq(): Unit = { + amoPortReqMessage = None + } + + def fireAMOResp(resp: LitDCacheWordResp): Unit = { + val aid = resp.id + val amoT = amoIdMap(aid) + val amoReq = amoT.req.get + amoT.pairResp(resp) + amoIdMap.remove(aid) + outerAMO -= amoT + if (amoReq.cmd == M_XA_SWAP) { + insertMaskedWordRead(amoReq.addr, resp.data, amoReq.mask) + insertMaskedWordWrite(amoReq.addr, amoReq.data, amoReq.mask) + } + } + override def step(): Unit = { for (i <- 0 until portNum) { s2_loadTrans(i) = s1_loadTrans(i) @@ -183,4 +225,25 @@ class CoreAgent(ID: Int, name: String, addrStateMap: mutable.Map[BigInt, AddrSta outerStore.append(storeT) } + def addAMO(addr: BigInt): Unit = { + val amoT = new DCacheAMOCallerTrans() + + val wordCnt = rand.nextInt(8) + + val lgSize = rand.nextInt(4) + val rsize = 1 << lgSize + // addr must be aligned to size + val offset = (rand.nextInt(8) >> lgSize) << lgSize + val laddr = addr + wordCnt * 8 + offset + // generate mask from raddr and rsize + val mask = (BigInt(1) << rsize) - 1 + val wmask = mask << offset + val wdata = (0 until 4).foldLeft(BigInt(0))( + (d, _) => (d << 16) | BigInt(rand.nextInt(0xffff)) + ) + //TODO: only swap for now + amoT.prepareAMOSwap(addr, wdata, wmask) + outerAMO.append(amoT) + } + } \ No newline at end of file diff --git a/src/test/scala/cache/L1DTest/CoreTransatcion.scala b/src/test/scala/cache/L1DTest/CoreTransatcion.scala index 813945a01..4fd272ec0 100644 --- a/src/test/scala/cache/L1DTest/CoreTransatcion.scala +++ b/src/test/scala/cache/L1DTest/CoreTransatcion.scala @@ -6,7 +6,9 @@ import xiangshan.cache.MemoryOpConstants class LitDCacheWordReq( val cmd: BigInt, val addr: BigInt, + var data: BigInt = 0, val mask: BigInt, + var id: BigInt = 0, ) { } @@ -14,6 +16,7 @@ class LitDCacheWordResp( val data: BigInt, val miss: Boolean, val replay: Boolean, + var id: BigInt = 0, ) { } @@ -38,6 +41,7 @@ class LitDCacheLineResp( trait LitMemOp { val M_XRD: BigInt = MemoryOpConstants.M_XRD.litValue() val M_XWR: BigInt = MemoryOpConstants.M_XWR.litValue() + val M_XA_SWAP: BigInt = MemoryOpConstants.M_XA_SWAP.litValue() } class DCacheLoadTrans extends TLCTrans with LitMemOp { @@ -110,3 +114,34 @@ class DCacheStoreCallerTrans extends DCacheStoreTrans with TLCCallerTrans { } +class DCacheAMOTrans extends TLCTrans with LitMemOp { + var req: Option[LitDCacheWordReq] = None + var resp: Option[LitDCacheWordResp] = None +} + +class DCacheAMOCallerTrans extends DCacheAMOTrans with TLCCallerTrans { + var reqIssued: Option[Boolean] = None + + def prepareAMOSwap(addr: BigInt, data: BigInt, mask: BigInt): Unit = { + req = Some( + new LitDCacheWordReq( + cmd = M_XA_SWAP, + addr = addr, + data = data, + mask = mask, + ) + ) + reqIssued = Some(true) + } + + def issueReq(allodId: BigInt = 0): LitDCacheWordReq = { + req.get.id = allodId + reqIssued = Some(true) + req.get + } + + def pairResp(inResp: LitDCacheWordResp): Unit = { + resp = Some(inResp) + } +} + diff --git a/src/test/scala/cache/L1DTest/L1DTest.scala b/src/test/scala/cache/L1DTest/L1DTest.scala index 0a08e35fc..599971563 100644 --- a/src/test/scala/cache/L1DTest/L1DTest.scala +++ b/src/test/scala/cache/L1DTest/L1DTest.scala @@ -64,7 +64,7 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers val rand = new Random(0xbeef) val addr_pool = { - for (_ <- 0 until 16) yield BigInt(rand.nextInt(0xfff) << 12) | 0x80000000L.U.litValue() + for (_ <- 0 until 64) yield BigInt(rand.nextInt(0xfffff) << 6) | 0x80000000L.U.litValue() }.distinct.toList // align to block size val addr_list_len = addr_pool.length println(f"addr pool length: $addr_list_len") @@ -97,6 +97,10 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers c.io.dcacheIO.store.resp.initSink().setSinkClock(c.clock) c.io.dcacheIO.store.req.valid.poke(false.B) c.io.dcacheIO.store.resp.ready.poke(false.B) + c.io.dcacheIO.atomics.req.initSource().setSourceClock(c.clock) + c.io.dcacheIO.atomics.resp.initSink().setSinkClock(c.clock) + c.io.dcacheIO.atomics.req.valid.poke(false.B) + c.io.dcacheIO.atomics.resp.ready.poke(false.B) c.io.slaveIO.AChannel.initSink().setSinkClock(c.clock) c.io.slaveIO.CChannel.initSink().setSinkClock(c.clock) @@ -110,7 +114,7 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers c.io.slaveIO.DChannel.valid.poke(false.B) - val total_clock = 50000 + val total_clock = 500 c.reset.poke(true.B) c.clock.step(100) @@ -149,6 +153,14 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers } } } + if (coreAgent.outerAMO.size <= 0) { + if (true) { + for (i <- 0 until 4) { + val addr = getRandomElement(addr_pool, rand) + coreAgent.addAMO(addr) + } + } + } //========= core poke ============ val loadPortsReqValid = ListBuffer.fill(loadPortNum)(false) val loadPortsRespReady = ListBuffer.fill(loadPortNum)(true) @@ -182,6 +194,21 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers coreIO.store.req.valid.poke(storePortReqValid.B) coreIO.store.resp.ready.poke(storePortRespReady.B) + var amoPortReqValid = false + val amoPortRespReady = true + coreAgent.issueAMOReq() + val amoReq = coreAgent.peekAMOReq() + if (amoReq.isDefined) { + amoPortReqValid = true + coreIO.atomics.req.bits.cmd.poke(amoReq.get.cmd.U) + coreIO.atomics.req.bits.addr.poke(amoReq.get.addr.U) + coreIO.atomics.req.bits.data.poke(amoReq.get.data.U) + coreIO.atomics.req.bits.mask.poke(amoReq.get.mask.U) + coreIO.atomics.req.bits.meta.id.poke(amoReq.get.id.U) + } + coreIO.atomics.req.valid.poke(amoPortReqValid.B) + coreIO.atomics.resp.ready.poke(amoPortRespReady.B) + //========= slave ============ //randomly add when empty if (slaveAgent.innerProbe.size <= 2) { @@ -318,6 +345,21 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers coreAgent.fireStoreResp(storeM) } + val amoPortReqReady = peekBoolean(coreIO.atomics.req.ready) + if (amoPortReqValid && amoPortReqReady) { + coreAgent.fireAMOReq() + } + val amoPortRespValid = peekBoolean(coreIO.atomics.resp.valid) + if (amoPortRespValid && amoPortRespReady) { + val amoM = new LitDCacheWordResp( + data = peekBigInt(coreIO.atomics.resp.bits.data), + miss = false, + replay = false, + id = peekBigInt(coreIO.atomics.resp.bits.meta.id) + ) + coreAgent.fireAMOResp(amoM) + } + val lsqRespValid = peekBoolean(coreIO.lsq.valid) if (lsqRespValid) { val lsqM = new LitDCacheLineResp( @@ -332,6 +374,17 @@ class L1DCacheTest extends AnyFlatSpec with ChiselScalatestTester with Matchers c.clock.step() } + c.io.dcacheIO.load.foreach { l => + l.s1_kill.poke(true.B) +// l.s1_paddr.poke(0x80000000L.U) + l.req.valid.poke(false.B) + l.resp.ready.poke(true.B) + } + c.io.dcacheIO.store.req.valid.poke(false.B) + c.io.dcacheIO.store.resp.ready.poke(true.B) + c.io.dcacheIO.atomics.req.valid.poke(false.B) + c.io.dcacheIO.atomics.resp.ready.poke(true.B) + c.clock.step(10) } } } \ No newline at end of file diff --git a/src/test/scala/cache/TLCTest/TLCAgent.scala b/src/test/scala/cache/TLCTest/TLCAgent.scala index daeb8ef4b..7797eb519 100644 --- a/src/test/scala/cache/TLCTest/TLCAgent.scala +++ b/src/test/scala/cache/TLCTest/TLCAgent.scala @@ -302,6 +302,22 @@ class TLCAgent(ID: Int, name: String = "", addrStateMap: mutable.Map[BigInt, Add debugPrintln(f"MaskedWrite, Addr: $alignAddr%x ,old sbData:$oldData%x , new sbData: $res%x , mask:$alignMask%x") } + def insertMaskedWordWrite(addr:BigInt, newWordData: BigInt, wordByteMask: BigInt):Unit = { + //addr and mask must be aligned to block + val alignAddr = addrAlignBlock(addr) + val start_word = wordInBlock(addr) + val alignData = dataConcatWord(0, newWordData, start_word) + val alignMask = maskConcatWord(0, wordByteMask, start_word) + val addrState = getState(alignAddr) + //new data + val oldData = scoreboardRead(alignAddr) + val res = writeMaskedData(oldData, alignData, alignMask) + addrState.dirty = true + addrState.data = res + scoreboardWrite(alignAddr, res) + debugPrintln(f"MaskedWrite, Addr: $alignAddr%x ,old sbData:$oldData%x , new sbData: $res%x , mask:$alignMask%x") + } + //full block read def insertRead(addr: BigInt, readData: BigInt): Unit = { //Do not call masked read for performance -- GitLab