提交 67559d9e 编写于 作者: L LinJiawei

Merge remote-tracking branch 'origin/master' into xs-fpu

......@@ -3,7 +3,7 @@ name: EMU Test
on:
push:
branches: [ master, update-ci, xs-fpu]
branches: [ master, update-ci]
pull_request:
branches: [ master ]
......
......@@ -39,3 +39,15 @@ object ParallelLookUp {
ParallelMux(mapping.map(m => (m._1===key) -> m._2))
}
}
object ParallelMax {
def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt() > b.asUInt(),a, b).asTypeOf(xs.head))
}
}
object ParallelMin {
def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt() < b.asUInt(),a, b).asTypeOf(xs.head))
}
}
\ No newline at end of file
......@@ -76,6 +76,7 @@ class TrueLRU(n_ways: Int) {
nextState.zipWithIndex.tail.foldLeft((nextState.head.apply(n_ways-1,1),0)) { case ((pe,pi),(ce,ci)) => (Cat(ce.apply(n_ways-1,ci+1), pe), ci) }._1
}
def get_next_state(state: UInt, touch_ways: Seq[Valid[UInt]]): UInt = {
touch_ways.foldLeft(state)((prev, touch_way) => Mux(touch_way.valid, get_next_state(prev, touch_way.bits), prev))
}
......@@ -162,3 +163,66 @@ class SeqPLRU(n_sets: Int, n_ways: Int) extends SeqReplacementPolicy {
def way = plru_way
}
class SbufferLRU(n_ways: Int) {
def nBits = n_ways * n_ways
private val state_reg = RegInit(0.U(nBits.W))
def state_read = WireDefault(state_reg)
def get_next_state(state: UInt, touch_way: UInt): UInt = {
val nextState = Wire(Vec(n_ways, UInt(n_ways.W)))
val moreRecentVec = state.asTypeOf(Vec(n_ways, UInt(n_ways.W)))
val wayDec = UIntToOH(touch_way, n_ways)
val wayUpd = (~wayDec).asUInt()
nextState.zipWithIndex.foreach { case (e, i) =>
e := Mux(i.U === touch_way,
wayUpd,
moreRecentVec(i) & wayUpd
)
}
nextState.asUInt()
}
def get_next_state(state: UInt, touch_ways: Seq[Valid[UInt]]): UInt = {
touch_ways.foldLeft(state)((prev, touch_way) => Mux(touch_way.valid, get_next_state(prev, touch_way.bits), prev))
}
def access(touch_way: UInt) {
state_reg := get_next_state(state_reg, touch_way)
}
def access(touch_ways: Seq[Valid[UInt]]) {
when (ParallelOR(touch_ways.map(_.valid))) {
state_reg := get_next_state(state_reg, touch_ways)
}
}
def get_min_value(xs: Seq[(UInt,UInt)]): (UInt,UInt)= {
xs match {
case Seq(a) => a
case Seq(a, b) => (Mux(a._1<b._1,a._1,b._1),Mux(a._1<b._1,a._2,b._2))
case _ =>
get_min_value(Seq(get_min_value(xs take xs.size/2), get_min_value(xs drop xs.size/2)))
}
}
def get_replace_way(state: UInt, sbufferState:Seq[Bool]): UInt = {
val moreRecentVec = state.asTypeOf(Vec(n_ways, UInt(n_ways.W)))
val count = Wire(Vec(n_ways, UInt(log2Up(n_ways).W)))
for(i <- 0 until n_ways){
count(i) := Mux(sbufferState(i), PopCount(moreRecentVec(i)), ((1<<n_ways)-1).U)
}
count.zip((0 until n_ways).map(_.U))
get_min_value(count.zip((0 until n_ways).map(_.U)))._2
}
def way(sbufferState:Seq[Bool]) = get_replace_way(state_reg,sbufferState)
//def miss = access(way)
def hit = {}
def flush() = { state_reg := 0.U(nBits.W) }
//@deprecated("replace 'replace' with 'way' from abstract class ReplacementPolicy","Rocket Chip 2020.05")
//def replace: UInt = way
}
\ No newline at end of file
......@@ -9,7 +9,7 @@ import xiangshan.backend.exu.ExuParameters
import xiangshan.frontend._
import xiangshan.mem._
import xiangshan.backend.fu.HasExceptionNO
import xiangshan.cache.{ICache, DCache, DCacheParameters, ICacheParameters, PTW, Uncache}
import xiangshan.cache.{ICache, DCache, DCacheParameters, ICacheParameters, L1plusCacheParameters, PTW, Uncache}
import chipsalliance.rocketchip.config
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLBundleParameters, TLCacheCork, TLBuffer, TLClientNode, TLIdentityNode, TLXbar}
......@@ -172,7 +172,12 @@ trait HasXSParameter {
val icacheParameters = ICacheParameters(
)
val LRSCCycles = 100
val l1plusCacheParameters = L1plusCacheParameters(
tagECC = Some("secded"),
dataECC = Some("secded"),
nMissEntries = 8
)
val dcacheParameters = DCacheParameters(
tagECC = Some("secded"),
dataECC = Some("secded"),
......@@ -180,6 +185,8 @@ trait HasXSParameter {
nLoadMissEntries = 8,
nStoreMissEntries = 8
)
val LRSCCycles = 100
}
trait HasXSLog { this: RawModule =>
......
......@@ -3,7 +3,6 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.ExcitingUtils.{ConnectionType, Debug}
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import fpu.Fflags
import utils._
import xiangshan._
......@@ -411,11 +410,6 @@ class CSR extends XSModule
// val setLrAddr = WireInit(UInt(AddrBits.W), DontCare) //TODO : need check
// val lr = RegInit(Bool(), false.B)
// val lrAddr = RegInit(UInt(AddrBits.W), 0.U)
// BoringUtils.addSink(setLr, "set_lr")
// BoringUtils.addSink(setLrVal, "set_lr_val")
// BoringUtils.addSink(setLrAddr, "set_lr_addr")
// BoringUtils.addSource(lr, "lr")
// BoringUtils.addSource(lrAddr, "lr_addr")
//
// when(setLr){
// lr := setLrVal
......@@ -855,14 +849,6 @@ class CSR extends XSModule
}
}
// for differential testing
// BoringUtils.addSource(RegNext(priviledgeMode), "difftestMode")
// BoringUtils.addSource(RegNext(mstatus), "difftestMstatus")
// BoringUtils.addSource(RegNext(mstatus & sstatusRmask), "difftestSstatus")
// BoringUtils.addSource(RegNext(mepc), "difftestMepc")
// BoringUtils.addSource(RegNext(sepc), "difftestSepc")
// BoringUtils.addSource(RegNext(mcause), "difftestMcause")
// BoringUtils.addSource(RegNext(scause), "difftestScause")
ExcitingUtils.addSource(priviledgeMode, "difftestMode", Debug)
ExcitingUtils.addSource(mstatus, "difftestMstatus", Debug)
ExcitingUtils.addSource(mstatus & sstatusRmask, "difftestSstatus", Debug)
......@@ -882,6 +868,5 @@ class CSR extends XSModule
ExcitingUtils.addSource(mideleg, "difftestMideleg", Debug)
ExcitingUtils.addSource(medeleg, "difftestMedeleg", Debug)
} else {
// BoringUtils.addSource(readWithScala(perfCntList("Minstret")._1), "ilaInstrCnt")
}
}
......@@ -177,7 +177,7 @@ object FunctionUnit {
val fmiscCfg =
FuConfig(FuType.fmisc, 0, 2, writeIntRf = false, writeFpRf = true, hasRedirect = false,
CertainLatency(2)
UncertainLatency()
)
val fDivSqrtCfg =
......
......@@ -7,7 +7,6 @@ import xiangshan._
import utils._
import xiangshan.backend.LSUOpType
import xiangshan.backend.fu.fpu.Fflags
import xiangshan.backend.decode.isa.Privileged.WFI
class RoqPtr extends CircularQueuePtr(RoqPtr.RoqSize) with HasCircularQueuePtrHelper {
......@@ -396,7 +395,6 @@ class Roq extends XSModule with HasCircularQueuePtrHelper {
ExcitingUtils.addSource(RegNext(retirePCFix), "difftestThisPC", ExcitingUtils.Debug)//first valid PC
ExcitingUtils.addSource(RegNext(retireInstFix), "difftestThisINST", ExcitingUtils.Debug)//first valid inst
ExcitingUtils.addSource(RegNext(skip.asUInt), "difftestSkip", ExcitingUtils.Debug)
// BoringUtils.addSource(RegNext(false.B), "difftestIsRVC")//FIXIT
ExcitingUtils.addSource(RegNext(isRVC.asUInt), "difftestIsRVC", ExcitingUtils.Debug)
ExcitingUtils.addSource(RegNext(wen.asUInt), "difftestWen", ExcitingUtils.Debug)
ExcitingUtils.addSource(RegNext(wpc), "difftestWpc", ExcitingUtils.Debug)
......
此差异已折叠。
......@@ -14,7 +14,7 @@ trait HasPdconst{ this: XSModule =>
val brType::Nil = ListLookup(instr, List(BrType.notBr), PreDecodeInst.brTable)
val rd = Mux(isRVC(instr), instr(12), instr(11,7))
val rs = Mux(isRVC(instr), Mux(brType === BrType.jal, 0.U, instr(11, 7)), instr(19, 15))
val isCall = (brType === BrType.jal || brType === BrType.jalr) && isLink(rd)
val isCall = (brType === BrType.jal && !isRVC(instr) || brType === BrType.jalr) && isLink(rd) // Only for RV64
val isRet = brType === BrType.jalr && isLink(rs) && !isCall
List(brType, isCall, isRet)
}
......
......@@ -106,7 +106,7 @@ class RAS extends BasePredictor
//update commit ras
val commit_push = !commit_is_full && io.recover.valid && io.recover.bits.pd.isCall
val commit_pop = !commit_is_empty && io.recover.valid && io.recover.bits.pd.isRet
val commit_new_addr = io.recover.bits.pc + 4.U //TODO: consider RVC
val commit_new_addr = Mux(io.recover.bits.pd.isRVC,io.recover.bits.pc + 2.U,io.recover.bits.pc + 4.U)
val commit_ras_write = WireInit(0.U.asTypeOf(rasEntry()))
val commit_alloc_new = commit_new_addr =/= commit_ras_top_addr
when (commit_push) {
......@@ -202,4 +202,4 @@ class RAS extends BasePredictor
// }
// }
}
\ No newline at end of file
}
......@@ -70,7 +70,8 @@ class NewSbuffer extends XSModule with HasSbufferCst {
val buffer = Mem(StoreBufferSize, new SbufferLine)
val stateVec = RegInit(VecInit(Seq.fill(StoreBufferSize)(s_invalid)))
val lru = new TrueLRU(StoreBufferSize)
//val lru = new SbufferLRU(StoreBufferSize)
val lru = new SbufferLRU(StoreBufferSize)
// 2 * enq + 1 * deq
val lruAccessWays = Wire(Vec(io.in.getWidth+1, new Valid(UInt(SbufferIndexWidth.W))))
for(w <- lruAccessWays){
......@@ -217,7 +218,7 @@ class NewSbuffer extends XSModule with HasSbufferCst {
val do_eviction = Wire(Bool())
val empty = Cat(stateVec.map(s => s===s_invalid)).andR() && !Cat(io.in.map(_.valid)).orR()
val replaceIdx = lru.way
val replaceIdx = lru.way(stateVec.map(s => s===s_valid))
val firstValidEntry = PriorityEncoder(stateVec.map(s => s===s_valid))
val evictor = Module(new NaiveEvictor(StoreBufferSize-4))
......@@ -248,6 +249,8 @@ class NewSbuffer extends XSModule with HasSbufferCst {
}
XSDebug(p"sbuffer state:${sbuffer_state} do eviction:${do_eviction} empty:${empty}\n")
//XSDebug(p"replaceIdx:${replaceIdx}\n")
//val evictionIdxWire = replaceIdx
val evictionIdxWire = Mux(stateVec(replaceIdx)===s_valid, replaceIdx, firstValidEntry)
val evictionIdxEnqReq = Wire(DecoupledIO(UInt(SbufferIndexWidth.W)))
val evictionIdxQueue = Module(new Queue(UInt(SbufferIndexWidth.W), StoreBufferSize, pipe = true, flow = false))
......
......@@ -115,16 +115,15 @@ void init_ram(const char *img) {
//new end
}
extern "C" void ram_helper(
uint64_t rIdx, uint64_t *rdata, uint64_t wIdx, uint64_t wdata, uint64_t wmask, uint8_t wen) {
extern "C" uint64_t ram_read_helper(uint64_t rIdx) {
if (rIdx >= RAMSIZE / sizeof(uint64_t)) {
printf("ERROR: ram idx = 0x%x out of bound!\n", rIdx);
// TODO: don't allow out of bound when crossbar is ready
//assert(rIdx < RAMSIZE / sizeof(uint64_t));
*rdata = 0xabcd12345678dcbaUL;
return;
assert(rIdx < RAMSIZE / sizeof(uint64_t));
}
*rdata = ram[rIdx];
return ram[rIdx];
}
extern "C" void ram_write_helper(uint64_t wIdx, uint64_t wdata, uint64_t wmask, uint8_t wen) {
if (wen) {
assert(wIdx < RAMSIZE / sizeof(uint64_t));
ram[wIdx] = (ram[wIdx] & ~wmask) | (wdata & wmask);
......
package cache
import scala.collection.mutable.ArrayBuffer
import chipsalliance.rocketchip.config.{Field, Parameters}
import chisel3._
import chisel3.util._
import chiseltest.experimental.TestOptionBuilder._
import chiseltest.internal.VerilatorBackendAnnotation
import chiseltest._
import chisel3.experimental.BundleLiterals._
import firrtl.stage.RunFirrtlTransformAnnotation
import chiseltest.ChiselScalatestTester
import device.AXI4RAM
import freechips.rocketchip.amba.axi4.AXI4UserYanker
import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLBuffer, TLCacheCork, TLToAXI4, TLXbar}
import org.scalatest.{FlatSpec, Matchers}
import sifive.blocks.inclusivecache.{CacheParameters, InclusiveCache, InclusiveCacheMicroParameters}
import utils.{DebugIdentityNode, HoldUnless, XSDebug}
import xiangshan.{HasXSLog, MicroOp}
import xiangshan.cache.{DCache, L1plusCache, DCacheLineIO, L1plusCacheIO, MemoryOpConstants}
import xiangshan.testutils.AddSinks
import xstransforms.PrintModuleName
import scala.util.Random
case object L1plusCacheTestKey extends Field[Long]
class L1plusTestTopIO extends Bundle {
val l1plus = new L1plusCacheIO()
val dcacheStore = new DCacheLineIO()
}
class L1plusTestTop()(implicit p: Parameters) extends LazyModule{
val dcache = LazyModule(new DCache())
val l1plusCache = LazyModule(new L1plusCache())
val l2 = LazyModule(new InclusiveCache(
CacheParameters(
level = 2,
ways = 4,
sets = 4 * 1024 / (64 * 4 * 4),
blockBytes = 64,
beatBytes = 32,
cacheName = s"L2"
),
InclusiveCacheMicroParameters(
writeBytes = 8
)
))
val ram = LazyModule(new AXI4RAM(
AddressSet(0x0L, 0xffffffffffL),
memByte = 128 * 1024 * 1024,
useBlackBox = false
))
val xbar = TLXbar()
xbar := TLBuffer() := dcache.clientNode
xbar := TLBuffer() := l1plusCache.clientNode
l2.node := xbar
ram.node :=
AXI4UserYanker() :=
TLToAXI4() :=
TLBuffer() :=
TLCacheCork() :=
l2.node
lazy val module = new LazyModuleImp(this) with HasXSLog {
val io = IO(Flipped(new L1plusTestTopIO))
AddSinks()
dcache.module.io <> DontCare
dcache.module.io.lsu.store <> io.dcacheStore
l1plusCache.module.io <> io.l1plus
}
}
class L1plusCacheTest extends FlatSpec with ChiselScalatestTester with Matchers {
behavior of "L1plusCache"
val mem_size = 128 * 1024 * 1024
val block_size = 64
// val nblocks = mem_size / block_size
val nblocks = 100
// data structures
// our golden version cache
val cache_blocks = new Array[BigInt](nblocks)
for (i <- 0 until nblocks) {
cache_blocks(i) = BigInt(0)
}
// ----------------------------------------
// useful request parameter values
val CMD_READ = MemoryOpConstants.M_XRD
val r = scala.util.Random
top.Parameters.set(top.Parameters.debugParameters)
val annos = Seq(
VerilatorBackendAnnotation,
RunFirrtlTransformAnnotation(new PrintModuleName)
)
it should "run" in {
implicit val p = Parameters((site, up, here) => {
case L1plusCacheTestKey => 0
})
test(LazyModule(new L1plusTestTop()).module)
.withAnnotations(annos){ c =>
c.clock.step(100)
val sq = new StoreQueue(8)
val lq = new LoadQueue(8)
def init() = {
sq.init()
lq.init()
// initialize DUT inputs
c.io.dcacheStore.req.valid.poke(false.B)
c.io.dcacheStore.resp.ready.poke(false.B)
c.io.l1plus.req.valid.poke(false.B)
c.io.l1plus.resp.ready.poke(false.B)
c.io.l1plus.flush.poke(false.B)
}
def flush_l1plus() = {
c.io.l1plus.flush.poke(true.B)
while (!c.io.l1plus.empty.peek().litToBoolean) {
c.clock.step()
}
c.io.l1plus.flush.poke(false.B)
}
def evaluate() = {
while (!sq.isFinished() || !lq.isFinished()) {
sq.tick(c.io.dcacheStore)
lq.tick(c.io.l1plus)
c.clock.step()
}
}
// ----------------------------------------
// scan test
// write every memory block and then read out every memory cell
def scan_test() = {
println(s"scan test")
init()
// first, initialize every memory block with random numbers
for (i <- 0 until nblocks) {
val addr = i * 64
val words = (0 until 8) map { _ =>
(BigInt(r.nextLong() & 0x7fffffffffffffffL))
}
val data = words.foldLeft(BigInt(0))((sum, i) => sum << 64 | i)
cache_blocks(i) = data
println(f"enq store addr: $addr%x data: $data%x")
sq.enq(Req(addr, data))
}
// execute reqs
evaluate()
// read them out
for (i <- 0 until nblocks) {
val addr = i * 64
val data = cache_blocks(i)
println(f"enq load addr: $addr%x data: $data%x")
lq.enq(Req(addr, data))
}
// execute reqs
evaluate()
}
scan_test()
// self_modify_test
def self_modify_test() = {
println(s"self_modify_test")
for (i <- 0 until 10) {
flush_l1plus()
scan_test()
}
}
self_modify_test()
}
}
}
// emulated queue
class IdPool(val nReqIds: Int) {
val freeIds = new Array[Boolean](nReqIds)
def allocate(): Int = {
for (i <- 0 until freeIds.size) {
if (freeIds(i)) {
freeIds(i) = false
return i
}
}
// no free id to allocate
return -1
}
def free(id: Int): Unit = {
assert(!freeIds(id))
freeIds(id) = true
}
def init(): Unit = {
for (i <- 0 until freeIds.size) {
freeIds(i) = true
}
}
}
case class Req(
addr: Long,
data: BigInt
) {
override def toString() : String = {
return f"addr: $addr%x data: $data%x"
}
}
case class QueueEntry(
var id: Int, // it's transaction id
req: Req
) {
override def toString() : String = {
return f"id: $id%d req: $req"
}
}
class Queue(nEntries: Int, name: String) {
// Queue
// ---------------------------------------
val idPool = new IdPool(nEntries)
val queue = new ArrayBuffer[QueueEntry]()
def enq(req: Req) = {
// for unissued reqs, they have id = -1
queue += new QueueEntry(-1, req)
}
// select a req to issue
// req with id == -1 are not issued
def select(): Int = {
for (i <- 0 until queue.size) {
if (queue(i).id == -1)
return i
}
return -1
}
// retire the req with transaction id tId
def retire(tId: Int): Unit = {
println(f"$name retire transaction: $tId%d")
for (i <- 0 until queue.size) {
if (queue(i).id == tId) {
// remove this request
queue.remove(i)
println(f"$name retire req: $i%d transaction: $tId%d")
return
}
}
assert(false)
}
def issue(idx: Int, tId: Int) = {
println(f"$name issue req: $idx%d transaction: $tId%d")
assert(queue(idx).id == -1)
queue(idx).id = tId
}
// look up req by transaction id tId
def lookUp(tId: Int): Req = {
for (i <- 0 until queue.size) {
if (queue(i).id == tId) {
// remove this request
return queue(i).req
}
}
// we must return a value
// just to make scala happy
return Req(0, 0)
}
var reqWaiting = false
def init(): Unit = {
idPool.init()
queue.clear()
reqWaiting = false
}
def isFinished() = queue.isEmpty
}
class StoreQueue(nEntries: Int) extends Queue(nEntries, "StoreQueue") {
def sendReq(port: DCacheLineIO): Unit = {
val req = port.req
// has last cycle's req been fired?
if (reqWaiting && req.ready.peek().litToBoolean) {
reqWaiting = false
// no requests waiting on line
// reset valid signal
req.valid.poke(false.B)
}
// can we send a new request in this cycle
val reqIdx = select()
if (reqWaiting || reqIdx == -1) {
return
}
val tId = idPool.allocate()
if (tId == -1) {
return
}
// try sending a new request in this cycle
// select a req to issue
reqWaiting = true
issue(reqIdx, tId)
val CMD_WRITE = MemoryOpConstants.M_XWR
val FULL_MASK = BigInt("ffffffffffffffff", 16).U
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_WRITE)
req.bits.addr.poke(r.addr.U)
req.bits.data.poke(r.data.U)
req.bits.mask.poke(FULL_MASK)
req.bits.meta.id.poke(tId.U)
req.bits.meta.vaddr.poke(r.addr.U)
req.bits.meta.paddr.poke(r.addr.U)
// req.bits.meta.uop.poke(0.U.asTypeOf(new MicroOp))
req.bits.meta.mmio.poke(false.B)
req.bits.meta.tlb_miss.poke(false.B)
req.bits.meta.mask.poke(FULL_MASK)
req.bits.meta.replay.poke(false.B)
}
def handleResp(port: DCacheLineIO) = {
val resp = port.resp
// always ready
resp.ready.poke(true.B)
if (resp.valid.peek().litToBoolean) {
val id = resp.bits.meta.id.peek().litValue.longValue.toInt
idPool.free(id)
retire(id)
}
}
def tick(port: DCacheLineIO) = {
// first, try to send reqs
sendReq(port)
// then, receive responses
handleResp(port)
}
}
class LoadQueue(nEntries: Int) extends Queue(nEntries, "LoadQueue") {
def sendReq(port: L1plusCacheIO): Unit = {
val req = port.req
// has last cycle's req been fired?
if (reqWaiting && req.ready.peek().litToBoolean) {
reqWaiting = false
// no requests waiting on line
// reset valid signal
req.valid.poke(false.B)
}
// can we send a new request in this cycle
val reqIdx = select()
if (reqWaiting || reqIdx == -1) {
return
}
val tId = idPool.allocate()
if (tId == -1) {
return
}
// try sending a new request in this cycle
// select a req to issue
reqWaiting = true
issue(reqIdx, tId)
val CMD_READ = MemoryOpConstants.M_XRD
val r = queue(reqIdx).req
req.valid.poke(true.B)
req.bits.cmd.poke(CMD_READ)
req.bits.addr.poke(r.addr.U)
req.bits.id.poke(tId.U)
}
def handleResp(port: L1plusCacheIO) = {
val resp = port.resp
// always ready
resp.ready.poke(true.B)
if (resp.valid.peek().litToBoolean) {
val id = resp.bits.id.peek().litValue.longValue.toInt
val rdata = resp.bits.data.peek().litValue
val r = lookUp(id)
assert(r.data == rdata)
idPool.free(id)
retire(id)
}
}
def tick(port: L1plusCacheIO) = {
// first, try to send reqs
sendReq(port)
// then, receive responses
handleResp(port)
}
}
package xiangshan.memend
import org.scalatest._
import chiseltest._
import chisel3._
import chisel3.experimental.BundleLiterals._
import chisel3.util._
import xiangshan._
import xiangshan.cache.{DCacheLineIO, DCacheWordReq}
import xiangshan.mem.{LoadForwardQueryIO, NewSbuffer}
import xiangshan.testutils._
import scala.util.Random
class SbufferWapper extends XSModule {
val io = IO(new Bundle() {
val in = Vec(StorePipelineWidth, Flipped(Decoupled(new DCacheWordReq)))
val dcache = new DCacheLineIO
val forward = Vec(LoadPipelineWidth, Flipped(new LoadForwardQueryIO))
val flush = new Bundle {
val valid = Input(Bool())
val empty = Output(Bool())
} // sbuffer flush
})
val sbuffer = Module(new NewSbuffer)
io <> sbuffer.io
// fake dcache
sbuffer.io.dcache.req.ready := true.B
sbuffer.io.dcache.resp.valid := RegNext(RegNext(RegNext(RegNext(sbuffer.io.dcache.req.valid))))
sbuffer.io.dcache.resp.bits.meta.id := RegNext(RegNext(RegNext(RegNext(sbuffer.io.dcache.req.bits.meta.id))))
}
class SbufferTest extends FlatSpec
with ChiselScalatestTester
with Matchers
with HasXSParameter
with ParallelTestExecution
with HasPartialDecoupledDriver {
top.Parameters.set(top.Parameters.debugParameters)
it should "random req" in {
test(new SbufferWapper{AddSinks()}){ c =>
def store_enq(addr: Seq[UInt], data: Seq[UInt], mask: Seq[UInt]) ={
(0 until StorePipelineWidth).map { i =>
c.io.in(i).valid.poke(true.B)
c.io.in(i).bits.pokePartial(chiselTypeOf(c.io.in(i).bits).Lit(
_.mask -> mask(i),
_.addr -> addr(i),
_.data -> data(i)
))
}
c.clock.step(1)
for (in <- c.io.in){ in.valid.poke(false.B)}
}
def forward_req_and_resp(addr: Seq[UInt], data: Seq[UInt], mask:Seq[UInt]) = {
(0 until LoadPipelineWidth).map{ i =>
c.io.forward(i).paddr.poke(addr(i))
c.io.forward(i).mask.poke(mask(i))
if(c.io.in(i).ready.peek() == true.B) {
(0 until 8).map { j =>
c.io.forward(i).forwardData(j).expect(data(i)(j * 8 + 7, j * 8))
}
}
}
}
val TEST_SIZE = 100
for(i <- 0 until TEST_SIZE) {
val addr = Seq.fill(StorePipelineWidth)((Random.nextLong() & 0x7ffffffff8L).U)// align to block size
val data = Seq.fill(StorePipelineWidth)((Random.nextLong() & 0x7fffffffffffffffL).U)
val mask = Seq.fill(StorePipelineWidth)(0xff.U)
store_enq(addr, data, mask)
forward_req_and_resp(addr, data, mask)
}
}
}
it should "sequence req" in {
test(new SbufferWapper{AddSinks()}){ c =>
def store_enq(addr: Seq[UInt], data: Seq[UInt], mask: Seq[UInt]) = {
(0 until StorePipelineWidth).map { i =>
c.io.in(i).valid.poke(true.B)
c.io.in(i).bits.pokePartial(chiselTypeOf(c.io.in(i).bits).Lit(
_.mask -> mask(i),
_.addr -> addr(i),
_.data -> data(i)
))
}
c.clock.step(1)
for (in <- c.io.in){ in.valid.poke(false.B)}
}
def forward_req_and_resp(addr: Seq[UInt], data: Seq[UInt], mask:Seq[UInt]) = {
(0 until LoadPipelineWidth).map{ i =>
c.io.forward(i).paddr.poke(addr(i))
c.io.forward(i).mask.poke(mask(i))
if(c.io.in(i).ready.peek() == true.B) {
(0 until 8).map { j =>
c.io.forward(i).forwardData(j).expect(data(i)(j * 8 + 7, j * 8))
}
}
}
}
val TEST_SIZE = 100
val start_addr = Random.nextLong() & 0x7ffffffff8L
for(i <- 0 until TEST_SIZE) {
val addr = Seq(((i<<4) + start_addr).U,((i<<4)+8+start_addr).U)
val data = Seq.fill(StorePipelineWidth)((Random.nextLong() & 0x7fffffffffffffffL).U)
val mask = Seq.fill(StorePipelineWidth)(0xff.U)
store_enq(addr, data, mask)
forward_req_and_resp(addr, data, mask)
}
}
}
}
import "DPI-C" function void ram_helper
import "DPI-C" function void ram_write_helper
(
input longint rIdx,
output longint rdata,
input longint wIdx,
input longint wdata,
input longint wmask,
input bit wen
);
import "DPI-C" function longint ram_read_helper
(
input longint rIdx
);
module RAMHelper(
input clk,
input [63:0] rIdx,
......@@ -18,8 +21,10 @@ module RAMHelper(
input wen
);
assign rdata = ram_read_helper(rIdx);
always @(posedge clk) begin
ram_helper(rIdx, rdata, wIdx, wdata, wmask, wen);
ram_write_helper(wIdx, wdata, wmask, wen);
end
endmodule
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册