diff options
author | Friedrich Beckmann <friedrich.beckmann@hs-augsburg.de> | 2022-07-25 17:55:39 +0200 |
---|---|---|
committer | Friedrich Beckmann <friedrich.beckmann@hs-augsburg.de> | 2022-07-25 17:55:39 +0200 |
commit | 3fff6023602822531efdae30bc8ebf862967f1ef (patch) | |
tree | 16028102b8d850f8ab3115d28a8539ca6bc5f51d /VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala |
Initial Commit
Diffstat (limited to 'VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala')
-rw-r--r-- | VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala new file mode 100644 index 0000000..22bc438 --- /dev/null +++ b/VexRiscv/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -0,0 +1,174 @@ +package vexriscv.demo + +import java.nio.{ByteBuffer, ByteOrder} + +import spinal.core._ +import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory} +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.misc.{HexTools, InterruptCtrl, Prescaler, Timer} +import spinal.lib._ +import spinal.lib.bus.simple._ +import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus} + +class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{ + val io = new Bundle{ + val iBus = slave(IBusSimpleBus(null)) + val dBus = slave(DBusSimpleBus(bigEndian)) + val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig)) + } + + io.masterBus.cmd.valid := io.iBus.cmd.valid || io.dBus.cmd.valid + io.masterBus.cmd.write := io.dBus.cmd.valid && io.dBus.cmd.wr + io.masterBus.cmd.address := io.dBus.cmd.valid ? io.dBus.cmd.address | io.iBus.cmd.pc + io.masterBus.cmd.data := io.dBus.cmd.data + io.masterBus.cmd.mask := io.dBus.genMask(io.dBus.cmd) + io.iBus.cmd.ready := io.masterBus.cmd.ready && !io.dBus.cmd.valid + io.dBus.cmd.ready := io.masterBus.cmd.ready + + + val rspPending = RegInit(False) clearWhen(io.masterBus.rsp.valid) + val rspTarget = RegInit(False) + when(io.masterBus.cmd.fire && !io.masterBus.cmd.write){ + rspTarget := io.dBus.cmd.valid + rspPending := True + } + + when(rspPending && !io.masterBus.rsp.valid){ + io.iBus.cmd.ready := False + io.dBus.cmd.ready := False + io.masterBus.cmd.valid := False + } + + io.iBus.rsp.valid := io.masterBus.rsp.valid && !rspTarget + io.iBus.rsp.inst := io.masterBus.rsp.data + io.iBus.rsp.error := False + + io.dBus.rsp.ready := io.masterBus.rsp.valid && rspTarget + io.dBus.rsp.data := io.masterBus.rsp.data + io.dBus.rsp.error := False +} + + +case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{ + val io = new Bundle{ + val bus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig)) + } + + val ram = Mem(Bits(32 bits), onChipRamSize / 4) + io.bus.rsp.valid := RegNext(io.bus.cmd.fire && !io.bus.cmd.write) init(False) + io.bus.rsp.data := ram.readWriteSync( + address = (io.bus.cmd.address >> 2).resized, + data = io.bus.cmd.data, + enable = io.bus.cmd.valid, + write = io.bus.cmd.write, + mask = io.bus.cmd.mask + ) + io.bus.cmd.ready := True + + if(onChipRamHexFile != null){ + HexTools.initRam(ram, onChipRamHexFile, 0x80000000l) + if(bigEndian) + // HexTools.initRam (incorrectly) assumes little endian byte ordering + for((word, wordIndex) <- ram.initialContent.zipWithIndex) + ram.initialContent(wordIndex) = + ((word & 0xffl) << 24) | + ((word & 0xff00l) << 8) | + ((word & 0xff0000l) >> 8) | + ((word & 0xff000000l) >> 24) + } +} + + + +case class Apb3Rom(onChipRamBinFile : String) extends Component{ + import java.nio.file.{Files, Paths} + val byteArray = Files.readAllBytes(Paths.get(onChipRamBinFile)) + val wordCount = (byteArray.length+3)/4 + val buffer = ByteBuffer.wrap(Files.readAllBytes(Paths.get(onChipRamBinFile))).order(ByteOrder.LITTLE_ENDIAN); + val wordArray = (0 until wordCount).map(i => { + val v = buffer.getInt + if(v < 0) BigInt(v.toLong & 0xFFFFFFFFl) else BigInt(v) + }) + + val io = new Bundle{ + val apb = slave(Apb3(log2Up(wordCount*4),32)) + } + + val rom = Mem(Bits(32 bits), wordCount) initBigInt(wordArray) +// io.apb.PRDATA := rom.readSync(io.apb.PADDR >> 2) + io.apb.PRDATA := rom.readAsync(RegNext(io.apb.PADDR >> 2)) + io.apb.PREADY := True +} + + + +class MuraxPipelinedMemoryBusDecoder(master : PipelinedMemoryBus, val specification : Seq[(PipelinedMemoryBus,SizeMapping)], pipelineMaster : Boolean) extends Area{ + val masterPipelined = PipelinedMemoryBus(master.config) + if(!pipelineMaster) { + masterPipelined.cmd << master.cmd + masterPipelined.rsp >> master.rsp + } else { + masterPipelined.cmd <-< master.cmd + masterPipelined.rsp >> master.rsp + } + + val slaveBuses = specification.map(_._1) + val memorySpaces = specification.map(_._2) + + val hits = for((slaveBus, memorySpace) <- specification) yield { + val hit = memorySpace.hit(masterPipelined.cmd.address) + slaveBus.cmd.valid := masterPipelined.cmd.valid && hit + slaveBus.cmd.payload := masterPipelined.cmd.payload.resized + hit + } + val noHit = !hits.orR + masterPipelined.cmd.ready := (hits,slaveBuses).zipped.map(_ && _.cmd.ready).orR || noHit + + val rspPending = RegInit(False) clearWhen(masterPipelined.rsp.valid) setWhen(masterPipelined.cmd.fire && !masterPipelined.cmd.write) + val rspNoHit = RegNext(False) init(False) setWhen(noHit) + val rspSourceId = RegNextWhen(OHToUInt(hits), masterPipelined.cmd.fire) + masterPipelined.rsp.valid := slaveBuses.map(_.rsp.valid).orR || (rspPending && rspNoHit) + masterPipelined.rsp.payload := slaveBuses.map(_.rsp.payload).read(rspSourceId) + + when(rspPending && !masterPipelined.rsp.valid) { //Only one pending read request is allowed + masterPipelined.cmd.ready := False + slaveBuses.foreach(_.cmd.valid := False) + } +} + +class MuraxApb3Timer extends Component{ + val io = new Bundle { + val apb = slave(Apb3( + addressWidth = 8, + dataWidth = 32 + )) + val interrupt = out Bool() + } + + val prescaler = Prescaler(16) + val timerA,timerB = Timer(16) + + val busCtrl = Apb3SlaveFactory(io.apb) + val prescalerBridge = prescaler.driveFrom(busCtrl,0x00) + + val timerABridge = timerA.driveFrom(busCtrl,0x40)( + ticks = List(True, prescaler.io.overflow), + clears = List(timerA.io.full) + ) + + val timerBBridge = timerB.driveFrom(busCtrl,0x50)( + ticks = List(True, prescaler.io.overflow), + clears = List(timerB.io.full) + ) + + val interruptCtrl = InterruptCtrl(2) + val interruptCtrlBridge = interruptCtrl.driveFrom(busCtrl,0x10) + interruptCtrl.io.inputs(0) := timerA.io.full + interruptCtrl.io.inputs(1) := timerB.io.full + io.interrupt := interruptCtrl.io.pendings.orR +} + + +object MuraxApb3TimerGen extends App{ + SpinalVhdl(new MuraxApb3Timer()) +}
\ No newline at end of file |