diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3a1a8a9..3c8f9c5 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -5,6 +5,7 @@ import vexriscv._ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.Axi4 +import spinal.lib.bus.misc.SizeMapping import scala.collection.mutable.ArrayBuffer @@ -27,6 +28,24 @@ trait DBusEncodingService { def loadData() : Bits } + +case class TightlyCoupledDataBus() extends Bundle with IMasterSlave { + val enable = Bool() + val address = UInt(32 bits) + val write_enable = Bool() + val write_data = Bits(32 bits) + val write_mask = Bits(4 bits) + val read_data = Bits(32 bits) + + override def asMaster(): Unit = { + out(enable, address, write_enable, write_data, write_mask) + in(read_data) + } +} + +case class TightlyCoupledDataPortParameter(name : String, hit : UInt => Bool) +case class TightlyCoupledDataPort(p : TightlyCoupledDataPortParameter, var bus : TightlyCoupledDataBus) + class DBusCachedPlugin(val config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, dBusCmdMasterPipe : Boolean = false, @@ -63,6 +82,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, args } + val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledDataPort]() + def tightlyGen = tightlyCoupledPorts.nonEmpty + + def newTightlyCoupledPort(mapping : UInt => Bool) = { + val port = TightlyCoupledDataPort(TightlyCoupledDataPortParameter(null, mapping), TightlyCoupledDataBus()) + tightlyCoupledPorts += port + port.bus + } override def addLoadWordEncoding(key : MaskedLiteral): Unit = { val decoderService = pipeline.service(classOf[DecoderService]) @@ -127,6 +154,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) object MEMORY_WR extends Stageable(Bool) + object MEMORY_TIGHTLY extends Stageable(Bits(tightlyCoupledPorts.size bits)) + object MEMORY_TIGHTLY_DATA extends Stageable(Bits(32 bits)) object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object MEMORY_FENCE extends Stageable(Bool) @@ -374,6 +403,25 @@ class DBusCachedPlugin(val config : DataCacheConfig, KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg()) ) } + + if(tightlyGen){ + insert(MEMORY_TIGHTLY) := B(tightlyCoupledPorts.map(_.p.hit(input(SRC_ADD).asUInt))) + when(insert(MEMORY_TIGHTLY).orR){ + cache.io.cpu.execute.isValid := False + arbitration.haltItself setWhen(stages.dropWhile(_ != execute).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR) + } + for((port, sel) <- (tightlyCoupledPorts, input(MEMORY_TIGHTLY).asBools).zipped){ + port.bus.enable := arbitration.isValid && input(MEMORY_ENABLE) && sel && !arbitration.isStuck + port.bus.address := input(SRC_ADD).asUInt.resized + port.bus.write_enable := input(MEMORY_WR) + port.bus.write_data := input(MEMORY_STORE_DATA_RF) + port.bus.write_mask := size.mux ( + U(0) -> B"0001", + U(1) -> B"0011", + default -> B"1111" + ) //|<< port.bus.address(1 downto 0) + } + } } val mmuAndBufferStage = if(writeBack != null) memory else execute @@ -391,6 +439,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, mmuBus.end := !arbitration.isStuck || arbitration.removeIt cache.io.cpu.memory.mmuRsp := mmuBus.rsp cache.io.cpu.memory.mmuRsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) + + if(tightlyGen){ + when(input(MEMORY_TIGHTLY).orR){ + cache.io.cpu.memory.isValid := False + input(HAS_SIDE_EFFECT) := False + } + insert(MEMORY_TIGHTLY_DATA) := OhMux(input(MEMORY_TIGHTLY), tightlyCoupledPorts.map(_.bus.read_data)) + } } val managementStage = stages.last @@ -465,7 +521,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, arbitration.haltItself.setWhen(cache.io.cpu.writeBack.isValid && cache.io.cpu.writeBack.haltIt) - val rspSplits = cache.io.cpu.writeBack.data.subdivideIn(8 bits) + val rspData = CombInit(cache.io.cpu.writeBack.data) + val rspSplits = rspData.subdivideIn(8 bits) val rspShifted = Bits(cpuDataWidth bits) //Generate minimal mux to move from a wide aligned memory read to the register file shifter representation for(i <- 0 until cpuDataWidth/8){ @@ -494,6 +551,16 @@ class DBusCachedPlugin(val config : DataCacheConfig, } insert(MEMORY_LOAD_DATA) := rspShifted + + if(tightlyGen){ + when(input(MEMORY_TIGHTLY).orR){ + cache.io.cpu.writeBack.isValid := False + exceptionBus.valid := False + redoBranch.valid := False + rspRf := input(MEMORY_TIGHTLY_DATA) + input(HAS_SIDE_EFFECT) := False + } + } } //Share access to the dBus (used by self refilled MMU) @@ -552,3 +619,55 @@ class DBusCachedPlugin(val config : DataCacheConfig, } + + +class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean = true) extends Plugin[VexRiscv]{ + var dbus : TightlyCoupledDataBus = null + var ibus : TightlyCoupledBus = null + + override def setup(pipeline: VexRiscv) = { + dbus = pipeline.service(classOf[DBusCachedPlugin]).newTightlyCoupledPort(addr => mapping.hit(addr)) + dbus.setCompositeName(this, "dbus").setAsDirectionLess() + + if(withIBus){ + ibus = pipeline.service(classOf[IBusCachedPlugin]).newTightlyCoupledPortV2( + TightlyCoupledPortParameter( + name = "tightlyCoupledIbus", + hit = addr => mapping.hit(addr) + ) + ) + ibus.setCompositeName(this, "ibus").setAsDirectionLess() + } + } + + override def build(pipeline: VexRiscv) = { + val logic = pipeline plug new Area { + val dBusAddressReg = RegNextWhen(dbus.address, dbus.enable) + val banks = for (id <- 0 to 3) yield new Area { + val ram = Mem.fill(mapping.size.toInt)(Bits(8 bits)) + val d = new Area { + val dataSel = id - dbus.address(1 downto 0) + val addr = (dbus.address + 3 - id) >> 2 + val write = dbus.write_data.subdivideIn(8 bits).read(dataSel) + val read = ram.readWriteSync( + address = addr.resized, + data = write, + enable = dbus.enable, + write = dbus.write_enable && dbus.write_mask(dataSel) + ) + } + val i = withIBus generate new Area { + val dataSel = id - ibus.address(1 downto 0) + val addr = (ibus.address + 3 - id) >> 2 + val read = ram.readSync( + address = addr.resized, + enable = ibus.enable + ) + } + } + + dbus.read_data := (0 to 3).map(id => banks.map(_.d.read).read(id + dBusAddressReg(1 downto 0))).asBits + if(withIBus) ibus.data := (0 to 3).map(id => banks(id).i.read).asBits + } + } +} diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 035c5dc..1bb15dc 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -82,6 +82,12 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, this } + def newTightlyCoupledPortV2(p : TightlyCoupledPortParameter) = { + val port = TightlyCoupledPort(p, master(TightlyCoupledBus())) + tightlyCoupledPorts += port + port.bus + } + object FLUSH_ALL extends Stageable(Bool) object IBUS_ACCESS_ERROR extends Stageable(Bool) @@ -149,7 +155,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val stageOffset = if(relaxedPcCalculation) 1 else 0 def stages = iBusRsp.stages.drop(stageOffset) - tightlyCoupledPorts.foreach(p => p.bus = master(TightlyCoupledBus()).setName(p.p.name)) + tightlyCoupledPorts.filter(_.bus == null).foreach(p => p.bus = master(TightlyCoupledBus()).setName(p.p.name)) val s0 = new Area { //address decoding