From d77e716719f635d79156dd2b1ff7592ec6191a87 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 26 Jan 2024 15:41:51 +0100 Subject: [PATCH] LsuL1 non coherent LR/SC implemented and pass tests --- src/main/scala/vexiiriscv/Param.scala | 6 +- .../scala/vexiiriscv/execute/lsu/Agu.scala | 6 +- .../vexiiriscv/execute/lsu/LsuL1Plugin.scala | 56 ++++++++++++++++--- .../vexiiriscv/execute/lsu/LsuPlugin.scala | 18 +++--- .../vexiiriscv/test/WhiteboxerPlugin.scala | 8 ++- .../scala/vexiiriscv/tester/Regression.scala | 2 +- 6 files changed, 70 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexiiriscv/Param.scala b/src/main/scala/vexiiriscv/Param.scala index 8b5ab240..0907349b 100644 --- a/src/main/scala/vexiiriscv/Param.scala +++ b/src/main/scala/vexiiriscv/Param.scala @@ -50,8 +50,8 @@ class ParamSimple(){ // Debug modifiers val debugParam = sys.env.getOrElse("VEXIIRISCV_DEBUG_PARAM", "0").toInt.toBoolean if(debugParam) { - decoders = 2 - lanes = 2 + decoders = 1 + lanes = 1 regFileSync = false withGShare = true withBtb = true @@ -67,7 +67,7 @@ class ParamSimple(){ privParam.withSupervisor = true privParam.withUser = true withMmu = false - withRva = false + withRva = true withRvc = false withAlignerBuffer = withRvc withFetchL1 = false diff --git a/src/main/scala/vexiiriscv/execute/lsu/Agu.scala b/src/main/scala/vexiiriscv/execute/lsu/Agu.scala index f7a66060..0e47cf22 100644 --- a/src/main/scala/vexiiriscv/execute/lsu/Agu.scala +++ b/src/main/scala/vexiiriscv/execute/lsu/Agu.scala @@ -38,7 +38,7 @@ class AguFrontend( if (XLEN.get == 64) writingRf ++= List(Rvi.LD, Rvi.LWU) if (RVF) writingRf ++= List(Rvfd.FLW) if (RVD) writingRf ++= List(Rvfd.FLD) - for (op <- writingRf) add(op).srcs(sk.Op.ADD, sk.SRC1.RF, sk.SRC2.I).decode(LR -> False, LOAD -> True) + for (op <- writingRf) add(op).srcs(sk.Op.ADD, sk.SRC1.RF, sk.SRC2.I).decode(LOAD -> True, LR -> False, SC -> False, AMO -> False) // Store stuff val storeOps = List(sk.Op.ADD, sk.SRC1.RF, sk.SRC2.S) @@ -62,11 +62,11 @@ class AguFrontend( for (amo <- uops) add(amo).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(AMO -> True, SC -> False, LOAD -> False, FLOAT -> False) writingMem += add(Rvi.SCW).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(AMO -> False, SC -> True, LOAD -> False, FLOAT -> False).uop writingRf += Rvi.SCW - writingRf += add(Rvi.LRW).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(LR -> True, LOAD -> True).uop + writingRf += add(Rvi.LRW).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(LR -> True, LOAD -> True, SC -> False, AMO -> False).uop if(XLEN.get == 64){ writingMem += add(Rvi.SCD).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(AMO -> False, SC -> True, LOAD -> False, FLOAT -> False).uop writingRf += Rvi.SCD - writingRf += add(Rvi.LRD).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(LR -> True, LOAD -> True).uop + writingRf += add(Rvi.LRD).srcs(sk.Op.SRC1, sk.SRC1.RF).decode(LR -> True, LOAD -> True, SC -> False, AMO -> False).uop } // assert(false, "Rvi.LR and atomic may need reformat info, CachelessPlugin may use loads list for it, need to add to loads. Also store completion need to be handled") } diff --git a/src/main/scala/vexiiriscv/execute/lsu/LsuL1Plugin.scala b/src/main/scala/vexiiriscv/execute/lsu/LsuL1Plugin.scala index 977c1847..7ebe9a0a 100644 --- a/src/main/scala/vexiiriscv/execute/lsu/LsuL1Plugin.scala +++ b/src/main/scala/vexiiriscv/execute/lsu/LsuL1Plugin.scala @@ -7,9 +7,10 @@ import spinal.lib.misc.pipeline._ import spinal.lib.misc.plugin.FiberPlugin import vexiiriscv.Global import vexiiriscv.misc.Reservation -import vexiiriscv.riscv.Riscv +import vexiiriscv.riscv.{AtomicAlu, Riscv} import vexiiriscv.execute._ import vexiiriscv.fetch.InitService +import vexiiriscv.riscv.Riscv.{RVA, RVC} object LsuL1 extends AreaObject{ // -> L1 @@ -20,10 +21,15 @@ object LsuL1 extends AreaObject{ val PHYSICAL_ADDRESS = Payload(Global.PHYSICAL_ADDRESS) val WRITE_DATA = Payload(Bits(Riscv.LSLEN bits)) val MASK = Payload(Bits(Riscv.LSLEN/8 bits)) //Also needed for loads + val AMO_OP = Payload(Bits(3 bits)) + val AMO_SWAP = Payload(Bool()) + val AMO_WORD = Payload(Bool()) // L1 -> + val WRITE_DATA_FINAL = Payload(Bits(Riscv.LSLEN bits)) val READ_DATA = Payload(Bits(Riscv.LSLEN bits)) val HAZARD, MISS, MISS_UNIQUE, FAULT = Payload(Bool()) + val SC_MISS = Payload(Bool()) } class LsuL1Plugin(val lane : ExecuteLaneService, @@ -122,7 +128,7 @@ class LsuL1Plugin(val lane : ExecuteLaneService, // val STATUS = Payload(Vec.fill(wayCount)(Status())) val BANKS_WORDS = Payload(Vec.fill(bankCount)(bankWord())) - val MUXED_DATA = Payload(Bits(cpuDataWidth bits)) + val MUXED_DATA, BYPASSED_DATA = Payload(Bits(cpuDataWidth bits)) val WAYS_TAGS = Payload(Vec.fill(wayCount)(Tag())) val WAYS_HITS = Payload(Bits(wayCount bits)) val WAYS_HIT = Payload(Bool()) @@ -142,7 +148,6 @@ class LsuL1Plugin(val lane : ExecuteLaneService, val EVENT_WRITE_ADDRESS = Payload(PHYSICAL_ADDRESS) val EVENT_WRITE_DATA = Payload(WRITE_DATA) val EVENT_WRITE_MASK = Payload(MASK) - val BANKS_MUXES = Payload(Vec.fill(bankCount)(Bits(cpuWordWidth bits))) val tagsWriteArbiter = new Reservation() @@ -844,11 +849,12 @@ class LsuL1Plugin(val lane : ExecuteLaneService, waysWrite.tag.loaded := False } + WRITE_DATA_FINAL := WRITE_DATA when(doWrite) { for ((bank, bankId) <- banks.zipWithIndex) when(WAYS_HITS(bankId)) { - bank.write.valid := bankId === bankHitId && allowSideEffects + bank.write.valid := bankId === bankHitId && allowSideEffects && !(SC && SC_MISS) bank.write.address := PHYSICAL_ADDRESS(lineRange.high downto log2Up(bankWidth / 8)) - bank.write.data.subdivideIn(cpuWordWidth bits).foreach(_ := WRITE_DATA) + bank.write.data.subdivideIn(cpuWordWidth bits).foreach(_ := WRITE_DATA_FINAL) bank.write.mask := 0 bank.write.mask.subdivideIn(cpuWordWidth / 8 bits)(PHYSICAL_ADDRESS(bankWordToCpuWordRange)) := MASK } @@ -857,7 +863,7 @@ class LsuL1Plugin(val lane : ExecuteLaneService, val brs = lane.execute(bankReadAt) brs(EVENT_WRITE_VALID) := doWrite brs(EVENT_WRITE_ADDRESS) := PHYSICAL_ADDRESS - brs(EVENT_WRITE_DATA) := WRITE_DATA + brs(EVENT_WRITE_DATA) := WRITE_DATA_FINAL brs(EVENT_WRITE_MASK) := MASK @@ -882,7 +888,7 @@ class LsuL1Plugin(val lane : ExecuteLaneService, plruLogic.core.io.update.id := wayId } - READ_DATA := MUXED_DATA + BYPASSED_DATA := MUXED_DATA val bypasser = if(withBypass) new Area { for (b <- widthOf(WRITE_TO_READ_HAZARDS) - 1 downto 0) { when(WRITE_TO_READ_HAZARDS(b)) { @@ -890,13 +896,47 @@ class LsuL1Plugin(val lane : ExecuteLaneService, val range = i * 8 + 7 downto i * 8 val src = lane.execute(bankReadAt+1+b) when(src(EVENT_WRITE_MASK)(i)) { - READ_DATA(range) := src(EVENT_WRITE_DATA)(range) + BYPASSED_DATA(range) := src(EVENT_WRITE_DATA)(range) } } } } } + READ_DATA := BYPASSED_DATA + + if (!RVA.get) { + SC_MISS := False + } + val rva = RVA.get generate new Area{ + val srcBuffer = RegNext[Bits](READ_DATA) + val alu = new AtomicAlu( + op = AMO_OP, + swap = AMO_SWAP, + mem = srcBuffer, + rf = WRITE_DATA, + isWord = AMO_WORD + ) + val aluBuffer = RegNext(alu.result) + when(AMO) { + WRITE_DATA_FINAL := aluBuffer +// READ_DATA := aluBuffer + } + val delay = History(!lane.isFreezed(), 1 to 2) + val freezeIt = SEL && AMO && delay.orR + lane.freezeWhen(freezeIt) //Note that if the refill is faster than 2 cycle, it may create issues + + assert(Global.HART_COUNT.get == 1) + assert(!withCoherency) + val nc = !withCoherency generate new Area{ + val reserved = RegInit(False) + when(!lane.isFreezed() && SEL && !ABORD){ + reserved setWhen(LR) + reserved clearWhen(!LOAD) + } + SC_MISS := !reserved + } + } // REFILL_SLOT_FULL := MISS && !refillHit && refill.full // REFILL_SLOT := REFILL_HITS.andMask(!refillLoaded) | refill.free.andMask(askRefill) diff --git a/src/main/scala/vexiiriscv/execute/lsu/LsuPlugin.scala b/src/main/scala/vexiiriscv/execute/lsu/LsuPlugin.scala index f60c6f85..947c7600 100644 --- a/src/main/scala/vexiiriscv/execute/lsu/LsuPlugin.scala +++ b/src/main/scala/vexiiriscv/execute/lsu/LsuPlugin.scala @@ -165,11 +165,15 @@ class LsuPlugin(var layer : LaneLayer, val freezeIt = doIt && !rsp.valid elp.freezeWhen(freezeIt) - - assert(!withRva) } val READ_DATA = insert(io.doIt.mux[Bits](io.rsp.data, l1.READ_DATA)) + val SC_MISS = insert(io.doIt.mux[Bool](io.rsp.scMiss, l1.SC_MISS)) + + + l1.AMO_OP := UOP(29, 3 bits) + l1.AMO_SWAP := UOP(27) + l1.AMO_WORD := SIZE === 2 flushPort.valid := False flushPort.hartId := Global.HART_ID @@ -187,8 +191,6 @@ class LsuPlugin(var layer : LaneLayer, trapPort.arg.allowOverride() := 0 val doTrap = False - - when(tpk.IO.mux[Bool](io.rsp.valid && io.rsp.error, l1.FAULT)) { doTrap := True trapPort.exception := True @@ -237,7 +239,6 @@ class LsuPlugin(var layer : LaneLayer, bypass(Global.COMMIT) := False } - l1.ABORD := FROM_LS && (!isValid || isCancel || tpk.IO || l1.FAULT || mmuPageFault || tpk.ACCESS_FAULT || tpk.REDO || MISS_ALIGNED) } @@ -259,10 +260,9 @@ class LsuPlugin(var layer : LaneLayer, iwb.valid := SEL iwb.payload := rspShifted - if (withRva) when(!LOAD && SC) { - ??? -// iwb.payload(0) := onJoin.SC_MISS -// iwb.payload(7 downto 1) := 0 + if (withRva) when(SC) { + iwb.payload(0) := onCtrl.SC_MISS + iwb.payload(7 downto 1) := 0 } } diff --git a/src/main/scala/vexiiriscv/test/WhiteboxerPlugin.scala b/src/main/scala/vexiiriscv/test/WhiteboxerPlugin.scala index 19aa2de4..453f1010 100644 --- a/src/main/scala/vexiiriscv/test/WhiteboxerPlugin.scala +++ b/src/main/scala/vexiiriscv/test/WhiteboxerPlugin.scala @@ -181,7 +181,7 @@ class WhiteboxerPlugin extends FiberPlugin{ uopId := c(Decode.UOP_ID) size := c(AguPlugin.SIZE) address := c(p.logic.tpk.TRANSLATED) - data := c(LsuL1.WRITE_DATA) + data := c(LsuL1.WRITE_DATA_FINAL) }) } @@ -201,7 +201,11 @@ class WhiteboxerPlugin extends FiberPlugin{ miss := c(p.logic.onJoin.SC_MISS) }) val lp = host.get[LsuPlugin] map (p => new Area { - fire := False + val c = p.logic.onWb + fire := c.down.isFiring && c(AguPlugin.SEL) && (c(AguPlugin.SC)) && !c(TRAP) + hartId := c(Global.HART_ID) + uopId := c(Decode.UOP_ID) + miss := c(p.logic.onCtrl.SC_MISS) }) } diff --git a/src/test/scala/vexiiriscv/tester/Regression.scala b/src/test/scala/vexiiriscv/tester/Regression.scala index 05437d0a..98c6096c 100644 --- a/src/test/scala/vexiiriscv/tester/Regression.scala +++ b/src/test/scala/vexiiriscv/tester/Regression.scala @@ -183,7 +183,7 @@ class RegressionSingle(compiled : SimCompiled[VexiiRiscv], args.name(s"freertos/$name") } - if(withBuildroot && rvm && rva) priv.filter(_.p.withSupervisor).foreach{ _ => + if(withBuildroot && rvm && rva && mmu.nonEmpty) priv.filter(_.p.withSupervisor).foreach{ _ => val path = s"ext/NaxSoftware/buildroot/images/$archLinux" val args = newArgs() args.failAfter(10000000000l)