From 468dd3841e2235297e31721e2205b8c43cb7576f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Jan 2018 13:16:40 +0100 Subject: [PATCH] Add Atomic LR SC support to the DBusCachedPlugin via reservation entries buffer --- src/main/scala/vexriscv/Riscv.scala | 3 ++ src/main/scala/vexriscv/TestsWorkspace.scala | 3 +- src/main/scala/vexriscv/ip/DataCache.scala | 44 ++++++++++++++++++- .../scala/vexriscv/plugin/CsrPlugin.scala | 11 ++++- .../vexriscv/plugin/DBusCachedPlugin.scala | 28 +++++++++++- src/test/scala/vexriscv/MuraxSim.scala | 1 + 6 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 85a753e..05e9488 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -59,6 +59,9 @@ object Riscv{ def SH = M"-----------------001-----0100011" def SW = M"-----------------010-----0100011" + def LR = M"00010--00000-----010-----0101111" + def SC = M"00011------------010-----0101111" + def BEQ = M"-----------------000-----1100011" def BNE = M"-----------------001-----1100011" def BLT = M"-----------------100-----1100011" diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 95d1314..b6fcfb7 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -75,7 +75,8 @@ object TestsWorkspace { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - catchMemoryTranslationMiss = true + catchMemoryTranslationMiss = true, + atomicEntriesCount = 2 ), // memoryTranslatorPortConfig = null memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 288b1f5..769d089 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -19,10 +19,12 @@ case class DataCacheConfig( cacheSize : Int, catchMemoryTranslationMiss : Boolean, clearTagsAfterReset : Boolean = true, waysHitRetime : Boolean = true, - tagSizeShift : Int = 0){ //Used to force infering ram + tagSizeShift : Int = 0, //Used to force infering ram + atomicEntriesCount : Int = 0){ def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError + def genAtomic = atomicEntriesCount != 0 def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, @@ -147,6 +149,7 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val size = UInt(2 bits) val forceUncachedAccess = Bool val clean, invalidate, way = Bool + val isAtomic = ifGen(p.genAtomic){Bool} // val all = Bool //Address should be zero when "all" is used } @@ -173,11 +176,13 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val data = Bits(p.cpuDataWidth bit) val mmuMiss, illegalAccess, unalignedAccess , accessError = Bool val badAddr = UInt(32 bits) + val clearAtomicEntries = ifGen(p.genAtomic) {Bool} // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { out(isValid,isStuck,isUser) in(haltIt, data, mmuMiss,illegalAccess , unalignedAccess, accessError, badAddr) + outWithNull(clearAtomicEntries) } } @@ -564,6 +569,38 @@ class DataCache(p : DataCacheConfig) extends Component{ } } + + val atomic = if(genAtomic) new Area{ + case class AtomicEntry() extends Bundle{ + val valid = Bool() + val size = UInt(2 bits) + val address = UInt(addressWidth bits) + + def init: this.type ={ + valid init(False) + this + } + } + val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) + val entriesAllocCounter = Counter(atomicEntriesCount) + val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === request.address).orR + when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){ + entries(entriesAllocCounter).valid := True + entries(entriesAllocCounter).size := request.size + entries(entriesAllocCounter).address := request.address + when(!io.cpu.writeBack.isStuck){ + entriesAllocCounter.increment() + } + } + when(io.cpu.writeBack.clearAtomicEntries){ + entries.foreach(_.valid := False) + } + + when(request.isAtomic && ! entriesHit){ + writeMask := 0 + } + } else null + when(io.cpu.writeBack.isValid) { if (catchMemoryTranslationMiss) { io.cpu.writeBack.mmuMiss := mmuRsp.miss @@ -638,6 +675,11 @@ class DataCache(p : DataCacheConfig) extends Component{ assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") io.cpu.writeBack.data := (request.forceUncachedAccess || mmuRsp.isIoAccess) ? io.mem.rsp.data | way.dataReadRspTwo //not multi ways + if(genAtomic){ + when(request.isAtomic && request.wr){ + io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized + } + } } //The whole life of a loading task, the corresponding manager request is present diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index cbc5771..6256645 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -138,9 +138,13 @@ case class CsrMapping(){ } +trait IContextSwitching{ + def isContextSwitching : Bool +} -class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor{ + +class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching{ import config._ import CsrAccess._ @@ -161,6 +165,8 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio var externalInterrupt : Bool = null var privilege : Bits = null var selfException : Flow[ExceptionCause] = null + var contextSwitching : Bool = null + override def isContextSwitching = contextSwitching object EnvCtrlEnum extends SpinalEnum(binarySequential){ val NONE, EBREAK, MRET= newElement() @@ -223,6 +229,7 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") + contextSwitching = Bool().setName("contextSwitching") privilege = RegInit(B"11") @@ -439,6 +446,8 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio } } + contextSwitching := jumpInterface.valid + //CSR read/write instructions management execute plug new Area { import execute._ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 9bf42b7..9d8b2f1 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -7,7 +7,6 @@ import spinal.lib._ - class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv]{ import config._ var dBus : DataCacheMemBus = null @@ -17,6 +16,7 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) + object MEMORY_ATOMIC extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -49,6 +49,30 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An List(SB, SH, SW).map(_ -> storeActions) ) + if(genAtomic){ + List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => + decoderService.add(e, Seq(MEMORY_ATOMIC -> False)) + ) + decoderService.add( + key = LR, + values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq( + RS2_USE -> True, + SRC2_CTRL -> Src2CtrlEnum.RS, + MEMORY_ATOMIC -> True + ) + ) + decoderService.add( + key = SC, + values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + MEMORY_ATOMIC -> True + ) + ) + } + def MANAGEMENT = M"-------00000-----101-----0001111" decoderService.add(MANAGEMENT, stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.RS, @@ -114,6 +138,7 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An cache.io.cpu.execute.args.clean := input(INSTRUCTION)(28) cache.io.cpu.execute.args.invalidate := input(INSTRUCTION)(29) cache.io.cpu.execute.args.way := input(INSTRUCTION)(30) + if(genAtomic) cache.io.cpu.execute.args.isAtomic := input(MEMORY_ATOMIC) insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0) } @@ -133,6 +158,7 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An cache.io.cpu.writeBack.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser(writeBack) else False) + if(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching if(catchSomething) { exceptionBus.valid := cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess diff --git a/src/test/scala/vexriscv/MuraxSim.scala b/src/test/scala/vexriscv/MuraxSim.scala index 0090f1f..5cc2637 100644 --- a/src/test/scala/vexriscv/MuraxSim.scala +++ b/src/test/scala/vexriscv/MuraxSim.scala @@ -25,6 +25,7 @@ object MuraxSim { val clockDomain = ClockDomain(dut.io.mainClk, dut.io.asyncReset) clockDomain.forkStimulus(mainClkPeriod) +// clockDomain.forkSimSpeedPrinter() val tcpJtag = JtagTcp( jtag = dut.io.jtag,