From 506e0e3f60cc89bb666e89bef11be13c3e7c2248 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 16 Feb 2018 02:21:08 +0100 Subject: [PATCH] New faster/smaller/multi way instruction cache design. Single or dual stage --- src/main/scala/vexriscv/Pipeline.scala | 1 + src/main/scala/vexriscv/Stage.scala | 2 + src/main/scala/vexriscv/TestsWorkspace.scala | 15 +- src/main/scala/vexriscv/VexRiscv.scala | 1 + .../scala/vexriscv/demo/FormalSimple.scala | 2 +- .../scala/vexriscv/demo/SynthesisBench.scala | 36 +- .../scala/vexriscv/ip/InstructionCache.scala | 365 +++++++----------- .../scala/vexriscv/plugin/DebugPlugin.scala | 52 ++- .../{FomalPlugin.scala => FormalPlugin.scala} | 2 +- .../plugin/HaltOnExceptionPlugin.scala | 8 +- .../vexriscv/plugin/IBusCachedPlugin.scala | 78 ++-- src/test/cpp/regression/main.cpp | 14 +- src/test/cpp/regression/makefile | 1 + src/test/scala/vexriscv/Play.scala | 119 ++++++ 14 files changed, 378 insertions(+), 318 deletions(-) rename src/main/scala/vexriscv/plugin/{FomalPlugin.scala => FormalPlugin.scala} (98%) create mode 100644 src/test/scala/vexriscv/Play.scala diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 7f555d3..86a2018 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -119,6 +119,7 @@ trait Pipeline { for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){ stage.arbitration.isStuckByOthers := stage.arbitration.haltByOther || stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.haltItself/* && !s.arbitration.removeIt*/).foldLeft(False)(_ || _) stage.arbitration.isStuck := stage.arbitration.haltItself || stage.arbitration.isStuckByOthers + stage.arbitration.isMoving := !stage.arbitration.isStuck && !stage.arbitration.removeIt stage.arbitration.isFiring := stage.arbitration.isValid && !stage.arbitration.isStuck && !stage.arbitration.removeIt } diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index 57d2a8d..c820754 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -48,11 +48,13 @@ class Stage() extends Area{ val haltByOther = False //When settable, stuck the instruction, should only be set by something else than the stucked instruction val removeIt = False //When settable, unschedule the instruction as if it was never executed (no side effect) val flushAll = False //When settable, unschedule instructions in the current stage and all prior ones + val redoIt = False //Allow to notify that a given instruction in a pipeline is rescheduled val isValid = RegInit(False) //Inform if a instruction is in the current stage val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther) val isStuckByOthers = Bool //Inform if the instruction is stuck by sombody else def isRemoved = removeIt //Inform if the instruction is going to be unschedule the current cycle val isFlushed = Bool //Inform if the instruction is flushed (flushAll set in the current or subsequents stages) + val isMoving = Bool //Inform if the instruction is going somewere else (next stage or unscheduled) val isFiring = Bool //Inform if the current instruction will go to the next stage the next cycle (isValid && !isStuck && !removeIt) } diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 15748d4..9c1b4a4 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -41,9 +41,9 @@ object TestsWorkspace { // ), new IBusCachedPlugin( config = InstructionCacheConfig( - cacheSize = 4096*4, - bytePerLine =32, - wayCount = 1, + cacheSize = 4096, + bytePerLine = 32, + wayCount = 4, wrappedMemAccess = true, addressWidth = 32, cpuDataWidth = 32, @@ -52,10 +52,11 @@ object TestsWorkspace { catchAccessFault = true, catchMemoryTranslationMiss = true, asyncTagMemory = false, - twoStageLogic = true + twoStageLogic = false, + twoCycleRam = true ), askMemoryTranslation = true, - memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + memoryTranslatorPortConfig = MemoryTranslatorPortConfig( portTlbSize = 4 ) ), @@ -95,7 +96,7 @@ object TestsWorkspace { catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.SYNC, + regFileReadyKind = plugin.ASYNC, zeroBoot = false ), new IntAluPlugin, @@ -122,7 +123,7 @@ object TestsWorkspace { new BranchPlugin( earlyBranch = true, catchAddressMisaligned = true, - prediction = DYNAMIC_TARGET, + prediction = NONE, historyRamSizeLog2 = 8 ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 606ca3f..44530af 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -66,6 +66,7 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ decode.input(config.INSTRUCTION).addAttribute(Verilator.public) decode.input(config.PC).addAttribute(Verilator.public) decode.arbitration.isValid.addAttribute(Verilator.public) + decode.arbitration.flushAll.addAttribute(Verilator.public) decode.arbitration.haltItself.addAttribute(Verilator.public) writeBack.input(config.INSTRUCTION) keep() addAttribute(Verilator.public) writeBack.input(config.PC) keep() addAttribute(Verilator.public) diff --git a/src/main/scala/vexriscv/demo/FormalSimple.scala b/src/main/scala/vexriscv/demo/FormalSimple.scala index 23761ab..0442790 100644 --- a/src/main/scala/vexriscv/demo/FormalSimple.scala +++ b/src/main/scala/vexriscv/demo/FormalSimple.scala @@ -11,7 +11,7 @@ object FormalSimple extends App{ def cpu() = new VexRiscv( config = VexRiscvConfig( plugins = List( - new FomalPlugin, + new FormalPlugin, new HaltOnExceptionPlugin, new PcManagerSimplePlugin( resetVector = 0x00000000l, diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 35b7f12..9175061 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -12,24 +12,24 @@ object VexRiscvSynthesisBench { def main(args: Array[String]) { def wrap(that : => Component) : Component = that - //Wrap with input/output registers - // def wrap(that : => Component) : Component = { - // //new WrapWithReg.Wrapper(that) - // val c = that - // c.rework { - // for (e <- c.getOrdredNodeIo) { - // if (e.isInput) { - // e.asDirectionLess() - // e := RegNext(RegNext(in(cloneOf(e)))) - // - // } else { - // e.asDirectionLess() - // out(cloneOf(e)) := RegNext(RegNext(e)) - // } - // } - // } - // c - // } +// Wrap with input/output registers +// def wrap(that : => Component) : Component = { +// //new WrapWithReg.Wrapper(that) +// val c = that +// c.rework { +// for (e <- c.getOrdredNodeIo) { +// if (e.isInput) { +// e.asDirectionLess() +// e := RegNext(RegNext(in(cloneOf(e)))) +// +// } else { +// e.asDirectionLess() +// out(cloneOf(e)) := RegNext(RegNext(e)) +// } +// } +// } +// c +// } val smallestNoCsr = new Rtl { override def getName(): String = "VexRiscv smallest no CSR" diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index eceec6f..87ffec2 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -18,7 +18,11 @@ case class InstructionCacheConfig( cacheSize : Int, catchAccessFault : Boolean, catchMemoryTranslationMiss : Boolean, asyncTagMemory : Boolean, - twoStageLogic : Boolean){ + twoStageLogic : Boolean, + twoCycleRam : Boolean = false, + preResetFlush : Boolean = false){ + + def dataOnDecode = twoCycleRam && wayCount > 1 def burstSize = bytePerLine*8/memDataWidth def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess @@ -47,72 +51,65 @@ case class InstructionCacheConfig( cacheSize : Int, case class InstructionCacheCpuPrefetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool - val isFiring = Bool val haltIt = Bool - val address = UInt(p.addressWidth bit) + val pc = UInt(p.addressWidth bit) override def asMaster(): Unit = { - out(isValid, isFiring, address) + out(isValid, pc) in(haltIt) } } case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave { val isValid = Bool - val haltIt = if(!p.twoStageLogic) Bool else null val isStuck = Bool - val isStuckByOthers = if(!p.twoStageLogic) Bool else null - val address = UInt(p.addressWidth bit) - val data = if(!p.twoStageLogic) Bits(32 bit) else null - val error = if(!p.twoStageLogic && p.catchAccessFault) Bool else null - val mmuBus = if(p.twoStageLogic) MemoryTranslatorBus() else null + val pc = UInt(p.addressWidth bits) + val data = Bits(p.cpuDataWidth bits) + val mmuBus = MemoryTranslatorBus() override def asMaster(): Unit = { - out(isValid, isStuck, address) - outWithNull(isStuckByOthers) - inWithNull(error,data,haltIt) + out(isValid, isStuck, pc) + inWithNull(data) slaveWithNull(mmuBus) } } + case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave { - require(p.twoStageLogic) val isValid = Bool - val haltIt = Bool - val isStuck = Bool val isUser = Bool - val address = UInt(p.addressWidth bit) - val data = Bits(32 bit) - val dataAnticipated = Bits(32 bits) + val isStuck = Bool + val pc = UInt(p.addressWidth bits) + val redo = Bool + val data = ifGen(p.dataOnDecode) (Bits(p.cpuDataWidth bits)) val error = if(p.catchAccessFault) Bool else null val mmuMiss = if(p.catchMemoryTranslationMiss) Bool else null val illegalAccess = if(p.catchIllegalAccess) Bool else null override def asMaster(): Unit = { - out(isValid, isStuck, address, isUser) - in(haltIt, data, dataAnticipated) - inWithNull(error,mmuMiss,illegalAccess) + out(isValid, isUser, isStuck, pc) + in(redo) + inWithNull(error,mmuMiss,illegalAccess,data) } } case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ val prefetch = InstructionCacheCpuPrefetch(p) val fetch = InstructionCacheCpuFetch(p) - val decode = if(p.twoStageLogic) InstructionCacheCpuDecode(p) else null + val decode = InstructionCacheCpuDecode(p) override def asMaster(): Unit = { - master(prefetch) - master(fetch) - if(p.twoStageLogic) master(decode) + master(prefetch, fetch, decode) } } case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{ val address = UInt(p.addressWidth bit) + val size = UInt(log2Up(log2Up(p.bytePerLine) + 1) bits) } case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{ - val data = Bits(32 bit) + val data = Bits(p.memDataWidth bit) val error = Bool } @@ -173,21 +170,21 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{ class InstructionCache(p : InstructionCacheConfig) extends Component{ import p._ - assert(wayCount == 1) - assert(cpuDataWidth == memDataWidth) + assert(cpuDataWidth == memDataWidth, "Need testing") val io = new Bundle{ val flush = slave(InstructionCacheFlushBus()) - // val translator = master(InstructionCacheTranslationBus(p)) val cpu = slave(InstructionCacheCpuBus(p)) val mem = master(InstructionCacheMemBus(p)) } - // val haltCpu = False + val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine val wordWidth = Math.max(memDataWidth,32) val wordWidthLog2 = log2Up(wordWidth) val wordPerLine = lineWidth/wordWidth + val memWordPerLine = lineWidth/memDataWidth val bytePerWord = wordWidth/8 + val bytePerMemWord = memDataWidth/8 val wayLineCount = lineCount/wayCount val wayLineLog2 = log2Up(wayLineCount) val wayWordCount = wayLineCount * wordPerLine @@ -195,44 +192,41 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine) val lineRange = tagRange.low-1 downto log2Up(bytePerLine) val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord) + val memWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerMemWord) + val memWordToCpuWordRange = log2Up(bytePerMemWord)-1 downto log2Up(bytePerWord) val tagLineRange = tagRange.high downto lineRange.low val lineWordRange = lineRange.high downto wordRange.low - class LineInfo extends Bundle{ + case class LineTag() extends Bundle{ val valid = Bool - val loading = Bool - val error = if(catchAccessFault) Bool else null + val error = Bool val address = UInt(tagRange.length bit) } - class LineInfoWithHit extends LineInfo{ - val hit = Bool - } - def LineInfoWithHit(lineInfo : LineInfo, testTag : UInt) = { - val ret = new LineInfoWithHit() - ret.assignSomeByName(lineInfo) - ret.hit := lineInfo.valid && lineInfo.address === testTag - ret - } + val ways = Seq.fill(wayCount)(new Area{ + val tags = Mem(LineTag(),wayLineCount) + val datas = Mem(Bits(memDataWidth bits),wayWordCount) - - val ways = Array.fill(wayCount)(new Area{ - val tags = Mem(new LineInfo(),wayLineCount) - val datas = Mem(Bits(wordWidth bits),wayWordCount) + if(preResetFlush){ + tags.initBigInt(List.fill(wayLineCount)(BigInt(0))) + } }) - io.cpu.prefetch.haltIt := False + + + val lineLoader = new Area{ - val requestIn = Stream(wrap(new Bundle{ - val addr = UInt(addressWidth bits) - })) + val fire = False + val valid = RegInit(False) clearWhen(fire) + val address = Reg(UInt(addressWidth bits)) + val hadError = RegInit(False) clearWhen(fire) + io.cpu.prefetch.haltIt setWhen(valid) - - val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(0) + val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0) when(!flushCounter.msb){ io.cpu.prefetch.haltIt := True flushCounter := flushCounter + 1 @@ -241,6 +235,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.prefetch.haltIt := True } val flushFromInterface = RegInit(False) + io.flush.cmd.ready := !(valid || io.cpu.fetch.isValid) //io.cpu.fetch.isValid will avoid bug on first cycle miss when(io.flush.cmd.valid){ io.cpu.prefetch.haltIt := True when(io.flush.cmd.ready){ @@ -251,204 +246,110 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.flush.rsp := flushCounter.msb.rise && flushFromInterface - val loadingWithErrorReg = if(catchAccessFault) RegInit(False) else null - val loadingWithError = if(catchAccessFault) Bool else null - if(catchAccessFault) { - loadingWithError := loadingWithErrorReg - loadingWithErrorReg := loadingWithError + + + val cmdSent = RegInit(False) setWhen(io.mem.cmd.fire) clearWhen(fire) + io.mem.cmd.valid := valid && !cmdSent + io.mem.cmd.address := address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) + io.mem.cmd.size := log2Up(p.bytePerLine) + + val wayToAllocate = Counter(wayCount, fire) + val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0) + + + val write = new Area{ + val tag = ways.map(_.tags.writePort) + val data = ways.map(_.datas.writePort) } + for(wayId <- 0 until wayCount){ + val wayHit = wayToAllocate === wayId + val tag = write.tag(wayId) + tag.valid := ((wayHit && fire) || !flushCounter.msb) + tag.address := (flushCounter.msb ? address(lineRange) | flushCounter(flushCounter.high-1 downto 0)) + tag.data.valid := flushCounter.msb + tag.data.error := hadError || io.mem.rsp.error + tag.data.address := address(tagRange) - - val request = requestIn.stage() - - - //Send memory requests - val memCmdSended = RegInit(False) setWhen(io.mem.cmd.fire) - io.mem.cmd.valid := request.valid && !memCmdSended - if(wrappedMemAccess) - io.mem.cmd.address := request.addr(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit) - else - io.mem.cmd.address := request.addr(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - - val wordIndex = Reg(UInt(log2Up(wordPerLine) bit)) - val loadedWordsNext = Bits(wordPerLine bit) - val loadedWords = RegNext(loadedWordsNext) - val loadedWordsReadable = RegNext(loadedWords) - loadedWordsNext := loadedWords - - val waysDatasWritePort = ways(0).datas.writePort //Not multi ways - waysDatasWritePort.valid := io.mem.rsp.valid - waysDatasWritePort.address := request.addr(lineRange) @@ wordIndex - waysDatasWritePort.data := io.mem.rsp.data - when(io.mem.rsp.valid){ - wordIndex := wordIndex + 1 - loadedWordsNext(wordIndex) := True - if(catchAccessFault) loadingWithError setWhen io.mem.rsp.error + val data = write.data(wayId) + data.valid := io.mem.rsp.valid && wayHit + data.address := address(lineRange) @@ wordIndex + data.data := io.mem.rsp.data } - val memRspLast = loadedWordsNext === B(loadedWordsNext.range -> true) - - val readyDelay = Reg(UInt(1 bit)) - when(memRspLast){ - readyDelay := readyDelay + 1 - } - request.ready := readyDelay === 1 - - val waysTagsWritePort = ways(0).tags.writePort //not multi way - waysTagsWritePort.valid := io.mem.rsp.valid || !flushCounter.msb - waysTagsWritePort.address := Mux(flushCounter.msb,request.addr(lineRange),flushCounter(flushCounter.high-1 downto 0)) - waysTagsWritePort.data.valid := flushCounter.msb - waysTagsWritePort.data.address := request.addr(tagRange) - waysTagsWritePort.data.loading := !memRspLast - if(catchAccessFault) waysTagsWritePort.data.error := loadingWithError - - - when(requestIn.ready){ - memCmdSended := False - wordIndex := requestIn.addr(wordRange) - loadedWords := 0 - loadedWordsReadable := 0 - readyDelay := 0 - if(catchAccessFault) loadingWithErrorReg := False + when(io.mem.rsp.valid) { + wordIndex := (wordIndex + 1).resized + hadError.setWhen(io.mem.rsp.error) + when(wordIndex === wordIndex.maxValue) { + fire := True + } } } - val task = if(!twoStageLogic) new Area{ - val waysHitValid = False - val waysHitError = Bool.assignDontCare() - val waysHitWord = Bits(wordWidth bit) - val waysRead = for(way <- ways) yield new Area{ - val readAddress = Mux(io.cpu.fetch.isStuck,io.cpu.fetch.address,io.cpu.prefetch.address) //TODO FMAX - val tag = if(asyncTagMemory) - way.tags.readAsync(io.cpu.fetch.address(lineRange),writeFirst) - else - way.tags.readSync(readAddress(lineRange),readUnderWrite = readFirst) - - val data = way.datas.readSync(readAddress(lineRange.high downto wordRange.low)) - waysHitWord := data //Not applicable to multi way - when(tag.valid && tag.address === io.cpu.fetch.address(tagRange)) { - waysHitValid := True - if(catchAccessFault) waysHitError := tag.error + val fetchStage = new Area{ + val read = new Area{ + val waysValues = for(way <- ways) yield new Area{ + val tag = if(asyncTagMemory) { + way.tags.readAsync(io.cpu.fetch.pc(lineRange)) + }else { + way.tags.readSync(io.cpu.prefetch.pc(lineRange), !io.cpu.fetch.isStuck) + } + val data = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck) } } - val hit = waysHitValid && !(waysRead(0).tag.loading && !(if(asyncTagMemory) lineLoader.loadedWords else RegNext(lineLoader.loadedWords))(io.cpu.fetch.address(wordRange))) - io.cpu.fetch.haltIt := io.cpu.fetch.isValid && !hit - io.cpu.fetch.data := waysHitWord - if(catchAccessFault) io.cpu.fetch.error := waysRead(0).tag.error - lineLoader.requestIn.valid := io.cpu.fetch.isValid && !hit //TODO avoid duplicated request - lineLoader.requestIn.addr := io.cpu.fetch.address - } else new Area{ - //Long readValidPath - // def writeFirstMemWrap[T <: Data](readValid : Bool, readAddress : UInt, lastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = { - // val hit = writeValid && (readValid ? readAddress | lastAddress) === writeAddress - // val overrideValid = RegInit(False) clearWhen(readValid) setWhen(hit) - // val overrideValue = RegNextWhen(writeData,hit) - // overrideValid ? overrideValue | readData - // } + val hit = if(!twoCycleRam) new Area{ + val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuBus.rsp.physicalAddress(tagRange)) + val valid = Cat(hits).orR + val id = OHToUInt(hits) + val error = read.waysValues.map(_.tag.error).read(id) + val data = read.waysValues.map(_.data).read(id) + val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + io.cpu.fetch.data := word + } else null - //shot readValid path - def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = { - val writeSample = readValid || (writeValid && writeAddress === readLastAddress) - val writeValidReg = RegNextWhen(writeValid,writeSample) - val writeAddressReg = RegNextWhen(writeAddress,writeSample) - val writeDataReg = RegNextWhen(writeData,writeSample) - (writeValidReg && writeAddressReg === readLastAddress) ? writeDataReg | readData + if(twoCycleRam && wayCount == 1){ + io.cpu.fetch.data := read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) } - //Long sample path - // def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,lastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) : (T,T) = { - // val hit = writeValid && (sample ? sampleAddress | lastAddress) === writeAddress - // val bypass = hit ? writeData | readData - // val reg = RegNextWhen(bypass,sample || hit) - // (reg,bypass) - // } - - //Short sample path - def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = { - val preWrite = (writeValid && sampleAddress === writeAddress) - val postWrite = (writeValid && sampleLastAddress === writeAddress) - val bypass = (!sample || preWrite) ? writeData | readData - val regEn = sample || postWrite - val reg = RegNextWhen(bypass,regEn) - (reg,bypass,regEn,preWrite,postWrite) - } - // def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = { - // val bypass = (!sample || (writeValid && sampleAddress === writeAddress)) ? writeData | readData - // val regEn = sample || (writeValid && sampleLastAddress === writeAddress) - // val reg = RegNextWhen(bypass,regEn) - // (reg,bypass,regEn,False,False) - // } - require(wayCount == 1) - val memRead = new Area{ - val way = ways(0) - val tag = if(asyncTagMemory) - way.tags.readAsync(io.cpu.fetch.address(lineRange),writeFirst) - else - writeFirstMemWrap( - readValid = !io.cpu.fetch.isStuck, - // readAddress = io.cpu.prefetch.address(lineRange), - readLastAddress = io.cpu.fetch.address(lineRange), - readData = way.tags.readSync(io.cpu.prefetch.address(lineRange),enable = !io.cpu.fetch.isStuck), - writeValid = lineLoader.waysTagsWritePort.valid, - writeAddress = lineLoader.waysTagsWritePort.address, - writeData = lineLoader.waysTagsWritePort.data - ) - - val data = writeFirstMemWrap( - readValid = !io.cpu.fetch.isStuck, - // readAddress = io.cpu.prefetch.address(lineWordRange), - readLastAddress = io.cpu.fetch.address(lineWordRange), - readData = way.datas.readSync(io.cpu.prefetch.address(lineWordRange),enable = !io.cpu.fetch.isStuck), - writeValid = lineLoader.waysDatasWritePort.valid, - writeAddress = lineLoader.waysDatasWritePort.address, - writeData = lineLoader.waysDatasWritePort.data - ) - } - - - val tag = writeFirstRegWrap( - sample = !io.cpu.decode.isStuck, - sampleAddress = io.cpu.fetch.address(lineRange), - sampleLastAddress = io.cpu.decode.address(lineRange), - readData = LineInfoWithHit(memRead.tag,io.cpu.fetch.address(tagRange)), - writeValid = lineLoader.waysTagsWritePort.valid, - writeAddress = lineLoader.waysTagsWritePort.address, - writeData = LineInfoWithHit(lineLoader.waysTagsWritePort.data,io.cpu.fetch.address(tagRange)) //TODO wrong address src - )._1 - - val (data,dataRegIn,dataRegEn,dataPreWrite,dataPostWrite) = writeFirstRegWrap( - sample = !io.cpu.decode.isStuck, - sampleAddress = io.cpu.fetch.address(lineWordRange), - sampleLastAddress = io.cpu.decode.address(lineWordRange), - readData = memRead.data, - writeValid = lineLoader.waysDatasWritePort.valid, - writeAddress = lineLoader.waysDatasWritePort.address, - writeData = lineLoader.waysDatasWritePort.data - ) - io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid - io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.address + io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc io.cpu.fetch.mmuBus.cmd.bypassTranslation := False - val mmuRsp = RegNextWhen(io.cpu.fetch.mmuBus.rsp,!io.cpu.decode.isStuck) - - val hit = tag.valid && tag.address === mmuRsp.physicalAddress(tagRange) && !(tag.loading && !lineLoader.loadedWords(mmuRsp.physicalAddress(wordRange))) - - io.cpu.decode.haltIt := io.cpu.decode.isValid && !hit //TODO PERF not halit it when removed, Should probably be applyed in many other places - io.cpu.decode.data := data - // io.cpu.decode.dataAnticipated := dataRegEn ? dataRegIn | data - io.cpu.decode.dataAnticipated := io.cpu.decode.isStuck ? Mux(dataPostWrite,lineLoader.waysDatasWritePort.data,data) | Mux(dataPreWrite,lineLoader.waysDatasWritePort.data,memRead.data) - if(catchAccessFault) io.cpu.decode.error := tag.error - if(catchMemoryTranslationMiss) io.cpu.decode.mmuMiss := mmuRsp.miss - if(catchIllegalAccess) io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) - - lineLoader.requestIn.valid := io.cpu.decode.isValid && !hit && !mmuRsp.miss//TODO avoid duplicated request - lineLoader.requestIn.addr := mmuRsp.physicalAddress } - io.flush.cmd.ready := !(lineLoader.request.valid || io.cpu.fetch.isValid || (if(twoStageLogic) io.cpu.decode.isValid else False)) + + val decodeStage = new Area{ + def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck) + val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp) + + val hit = if(!twoCycleRam) new Area{ + val valid = stage(fetchStage.hit.valid) + val error = stage(fetchStage.hit.error) + } else new Area{ + val tags = fetchStage.read.waysValues.map(way => stage(way.tag)) + val hits = tags.map(tag => tag.valid && tag.address === mmuRsp.physicalAddress(tagRange)) + val valid = Cat(hits).orR + val id = OHToUInt(hits) + val error = tags(id).error + if(dataOnDecode) { + val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id) + val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) + io.cpu.decode.data := word + } + } + + io.cpu.decode.redo := io.cpu.decode.isValid && !hit.valid + when(io.cpu.decode.redo){ + io.cpu.prefetch.haltIt := True + lineLoader.valid := True + lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used + } + + if(catchAccessFault) io.cpu.decode.error := hit.error + if(catchMemoryTranslationMiss) io.cpu.decode.mmuMiss := mmuRsp.miss + if(catchIllegalAccess) io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) + } } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index b73c788..6c83aec 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -1,14 +1,16 @@ package vexriscv.plugin import spinal.lib.com.jtag.Jtag -import spinal.lib.system.debugger.{SystemDebugger, JtagBridge, SystemDebuggerConfig} -import vexriscv.plugin.IntAluPlugin.{AluCtrlEnum, ALU_CTRL} +import spinal.lib.system.debugger.{JtagBridge, SystemDebugger, SystemDebuggerConfig} +import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum} import vexriscv._ import vexriscv.ip._ import spinal.core._ import spinal.lib._ -import spinal.lib.bus.amba3.apb.{Apb3Config, Apb3} -import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM} +import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config} +import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} + +import scala.collection.mutable.ArrayBuffer case class DebugExtensionCmd() extends Bundle{ @@ -92,10 +94,18 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ } } -class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { + +//Allow to avoid instruction cache plugin to be confused by new instruction poping in the pipeline +trait InstructionInjector{ + def isInjecting(stage : Stage) : Bool +} + +class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] with InstructionInjector { var io : DebugExtensionIo = null - + val injectionAsks = ArrayBuffer[(Stage, Bool)]() + var isInjectingOnDecode : Bool = null + override def isInjecting(stage: Stage) : Bool = if(stage == pipeline.decode) isInjectingOnDecode else False object IS_EBREAK extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { @@ -114,13 +124,15 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { SRC2_CTRL -> Src2CtrlEnum.PC, ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg )) + + isInjectingOnDecode = Bool() } override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ - debugClockDomain {pipeline plug new Area{ + val logic = debugClockDomain {pipeline plug new Area{ val insertDecodeInstruction = False val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready) val secondCycle = RegNext(firstCycle) @@ -168,12 +180,21 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { } } - //Assign the bus write data into the register who drive the decode instruction, even if it need to cross some hierarchy (caches) Component.current.addPrePopTask(() => { - val reg = decode.input(INSTRUCTION).getDrivingReg - reg.component.rework { - when(insertDecodeInstruction.pull()) { - reg := io.bus.cmd.data.pull() + //Check if the decode instruction is driven by a register + val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null} + if(instructionDriver != null){ //If yes => + //Insert the instruction by writing the "fetch to decode instruction register", + // Work even if it need to cross some hierarchy (caches) + instructionDriver.component.rework { + when(insertDecodeInstruction.pull()) { + instructionDriver := io.bus.cmd.data.pull() + } + } + } else{ + //Insert the instruction via a mux in the decode stage + when(RegNext(insertDecodeInstruction)){ + decode.input(INSTRUCTION) := RegNext(io.bus.cmd.data) } } }) @@ -193,7 +214,9 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { when(stepIt && prefetch.arbitration.isFiring) { haltIt := True } - + when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) { + haltIt := False + } io.resetOut := RegNext(resetIt) if(serviceExist(classOf[InterruptionInhibitor])) { @@ -207,5 +230,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { } } }} + + + isInjectingOnDecode := RegNext(logic.insertDecodeInstruction) init(False) } } diff --git a/src/main/scala/vexriscv/plugin/FomalPlugin.scala b/src/main/scala/vexriscv/plugin/FormalPlugin.scala similarity index 98% rename from src/main/scala/vexriscv/plugin/FomalPlugin.scala rename to src/main/scala/vexriscv/plugin/FormalPlugin.scala index e0e27eb..d46feba 100644 --- a/src/main/scala/vexriscv/plugin/FomalPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FormalPlugin.scala @@ -62,7 +62,7 @@ case class RvfiPort() extends Bundle with IMasterSlave { //2) JALR => clear PC(0) //3) input(INSTRUCTION)(5) REGFILE_WRITE_VALID memory read with exception would not fire properly -class FomalPlugin extends Plugin[VexRiscv]{ +class FormalPlugin extends Plugin[VexRiscv]{ var rvfi : RvfiPort = null diff --git a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala index 44c06a9..e6761de 100644 --- a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala +++ b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala @@ -28,11 +28,15 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService { stages.head.insert(FORMAL_HALT) := False stages.foreach(stage => { val stagePorts = exceptionPortsInfos.filter(_.stage == stage) - if(stagePorts.nonEmpty) - when(stagePorts.map(_.port.valid).orR){ + if(stagePorts.nonEmpty) { + when(stagePorts.map(info => info.port.valid).orR) { stage.output(FORMAL_HALT) := True stage.arbitration.haltItself := True } + for(stage <- stages){ + stage.output(FORMAL_HALT) clearWhen(stage.arbitration.isFlushed) + } + } }) } } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 0c67b7a..cfff932 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -8,15 +8,17 @@ import spinal.lib._ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] { import config._ - assert(twoStageLogic || !askMemoryTranslation) var iBus : InstructionCacheMemBus = null var mmuBus : MemoryTranslatorBus = null var decodeExceptionPort : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null + var redoBranch : Flow[UInt] = null object FLUSH_ALL extends Stageable(Bool) object IBUS_ACCESS_ERROR extends Stageable(Bool) + object IBUS_MMU_MISS extends Stageable(Bool) + object IBUS_ILLEGAL_ACCESS extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ @@ -29,6 +31,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B FLUSH_ALL -> True )) + //TODO manage priority with branch prediction + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode) + if(catchSomething) { val exceptionService = pipeline.service(classOf[ExceptionService]) decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1) @@ -68,59 +73,55 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B //Connect prefetch cache side cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid - cache.io.cpu.prefetch.isFiring := prefetch.arbitration.isFiring - cache.io.cpu.prefetch.address := prefetch.output(PC) + cache.io.cpu.prefetch.pc := prefetch.output(PC) prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt) //Connect fetch cache side cache.io.cpu.fetch.isValid := fetch.arbitration.isValid cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck - if(!twoStageLogic) cache.io.cpu.fetch.isStuckByOthers := fetch.arbitration.isStuckByOthers - cache.io.cpu.fetch.address := fetch.output(PC) - if(!twoStageLogic) { - fetch.arbitration.haltItself setWhen (cache.io.cpu.fetch.haltIt) + cache.io.cpu.fetch.pc := fetch.output(PC) + + if (mmuBus != null) { + cache.io.cpu.fetch.mmuBus <> mmuBus + } else { + cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress + cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True + cache.io.cpu.fetch.mmuBus.rsp.allowRead := True + cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True + cache.io.cpu.fetch.mmuBus.rsp.allowUser := True + cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False + cache.io.cpu.fetch.mmuBus.rsp.miss := False + } + + if(dataOnDecode){ + decode.insert(INSTRUCTION) := cache.io.cpu.decode.data + }else{ fetch.insert(INSTRUCTION) := cache.io.cpu.fetch.data decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION)) - decode.insert(INSTRUCTION_READY) := True - }else { - if (mmuBus != null) { - cache.io.cpu.fetch.mmuBus <> mmuBus - } else { - cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress - cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True - cache.io.cpu.fetch.mmuBus.rsp.allowRead := True - cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True - cache.io.cpu.fetch.mmuBus.rsp.allowUser := True - cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False - cache.io.cpu.fetch.mmuBus.rsp.miss := False - } } + decode.insert(INSTRUCTION_READY) := True + cache.io.cpu.decode.pc := decode.output(PC) + val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode)) + cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode + cache.io.cpu.decode.isStuck := decode.arbitration.isStuck + cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(decode) else False) +// cache.io.cpu.decode.pc := decode.input(PC) - if(twoStageLogic){ - cache.io.cpu.decode.isValid := decode.arbitration.isValid && RegNextWhen(fetch.arbitration.isValid, !decode.arbitration.isStuck) //avoid inserted instruction from debug module - decode.arbitration.haltItself.setWhen(cache.io.cpu.decode.haltIt) - cache.io.cpu.decode.isStuck := decode.arbitration.isStuck - cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(writeBack) else False) - cache.io.cpu.decode.address := decode.input(PC) - decode.insert(INSTRUCTION) := cache.io.cpu.decode.data - decode.insert(INSTRUCTION_ANTICIPATED) := cache.io.cpu.decode.dataAnticipated - decode.insert(INSTRUCTION_READY) := !cache.io.cpu.decode.haltIt + redoBranch.valid := cache.io.cpu.decode.redo + redoBranch.payload := decode.input(PC) + when(redoBranch.valid){ + decode.arbitration.redoIt := True + decode.arbitration.flushAll := True } - if(catchSomething){ - if(catchAccessFault) { - if (!twoStageLogic) fetch.insert(IBUS_ACCESS_ERROR) := cache.io.cpu.fetch.error - if (twoStageLogic) decode.insert(IBUS_ACCESS_ERROR) := cache.io.cpu.decode.error - } - - val accessFault = if(catchAccessFault) decode.input(IBUS_ACCESS_ERROR) else False + val accessFault = if(catchAccessFault) cache.io.cpu.decode.error else False val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False - decodeExceptionPort.valid := decode.arbitration.isValid && (accessFault || mmuMiss || illegalAccess) + decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess) decodeExceptionPort.code := mmuMiss ? U(14) | 1 decodeExceptionPort.badAddr := decode.input(PC) } @@ -130,11 +131,10 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B cache.io.flush.cmd.valid := False when(arbitration.isValid && input(FLUSH_ALL)){ cache.io.flush.cmd.valid := True + decode.arbitration.flushAll := True when(!cache.io.flush.cmd.ready){ arbitration.haltItself := True - } otherwise { - decode.arbitration.flushAll := True } } } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 30c93d3..27dda00 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -358,6 +358,10 @@ public: top->reset = 1; top->eval(); + top->clk = 1; + top->eval(); + top->clk = 0; + top->eval(); #ifdef CSR top->timerInterrupt = 0; top->externalInterrupt = 1; @@ -435,7 +439,7 @@ public: for(SimElement* simElement : simElements) simElement->preCycle(); if(withInstructionReadCheck){ - if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself){ + if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){ uint32_t expectedData; bool dummy; iBusAccess(top->VexRiscv->decode_PC, &expectedData, &dummy); @@ -598,7 +602,7 @@ public: virtual void preCycle(){ if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) { assertEq(top->iBus_cmd_payload_address & 3,0); - pendingCount = 8; + pendingCount = (1 << top->iBus_cmd_payload_size)/4; address = top->iBus_cmd_payload_address; } } @@ -610,7 +614,7 @@ public: ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error); top->iBus_rsp_payload_error = error; pendingCount--; - address = (address & ~0x1F) + ((address + 4) & 0x1F); + address = address + 4; top->iBus_rsp_valid = 1; } if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0; @@ -1606,7 +1610,7 @@ string riscvTestDiv[] = { }; string freeRtosTests[] = { - "AltBlock", "AltQTest", "AltBlckQ", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", + "AltBlckQ", "AltBlock", "AltQTest", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" //"flop", "sp_flop" // <- Simple test @@ -1714,7 +1718,7 @@ int main(int argc, char **argv, char **env) { #ifdef CSR uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u , 8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,17,1 }; - redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(4e4);) + redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);) #endif #ifdef MMU uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 3caee62..0d1be28 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -27,6 +27,7 @@ ADDCFLAGS += -CFLAGS -DREDO=${REDO} ADDCFLAGS += -CFLAGS -pthread ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT} + ifeq ($(DHRYSTONE),yes) ADDCFLAGS += -CFLAGS -DDHRYSTONE endif diff --git a/src/test/scala/vexriscv/Play.scala b/src/test/scala/vexriscv/Play.scala new file mode 100644 index 0000000..48abd5f --- /dev/null +++ b/src/test/scala/vexriscv/Play.scala @@ -0,0 +1,119 @@ +package vexriscv + +import spinal.core._ +import spinal.lib.master +import vexriscv.ip.InstructionCacheConfig +import vexriscv.plugin._ + +object PlayGen extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + config = InstructionCacheConfig( + cacheSize = 16, + bytePerLine = 4, + wayCount = 1, + wrappedMemAccess = false, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = false, + catchAccessFault = false, + catchMemoryTranslationMiss = false, + asyncTagMemory = false, + twoStageLogic = false, + preResetFlush = false + ), + askMemoryTranslation = false + ), + new FormalPlugin, + new HaltOnExceptionPlugin, + new PcManagerSimplePlugin( + resetVector = 0x00000000l, + relaxedPcCalculation = false + ), +// new IBusSimplePlugin( +// interfaceKeepData = false, +// catchAccessFault = false +// ), + new DBusSimplePlugin( + catchAddressMisaligned = true, + catchAccessFault = false + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true, + forceLegalInstructionComputation = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = false + ), + new FullBarrielShifterPlugin, + new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true, + prediction = NONE + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + // Wrap with input/output registers + def wrap(that : => VexRiscv) : Component = { + val c = that +// c.rework { +// for (e <- c.getOrdredNodeIo) { +// if (e.isInput) { +// e.asDirectionLess() +// e := RegNext(RegNext(in(cloneOf(e)))) +// +// } else { +// e.asDirectionLess() +// out(cloneOf(e)) := RegNext(RegNext(e)) +// } +// } +// } + + c.rework{ + c.config.plugins.foreach{ + case p : IBusCachedPlugin => { + p.iBus.asDirectionLess().unsetName() + val iBusNew = master(IBusSimpleBus(false)).setName("iBus") + + iBusNew.cmd.valid := p.iBus.cmd.valid + iBusNew.cmd.pc := p.iBus.cmd.address + p.iBus.cmd.ready := iBusNew.cmd.ready + + val pending = RegInit(False) clearWhen(iBusNew.rsp.ready) setWhen (iBusNew.cmd.fire) + p.iBus.rsp.valid := iBusNew.rsp.ready & pending + p.iBus.rsp.error := iBusNew.rsp.error + p.iBus.rsp.data := iBusNew.rsp.inst + } + case _ => + } + } + c + } + SpinalConfig( + defaultConfigForClockDomains = ClockDomainConfig( + resetKind = spinal.core.SYNC, + resetActiveLevel = spinal.core.HIGH + ), + inlineRom = true + ).generateVerilog(wrap(cpu())) +}